KiCad PCB EDA Suite
Loading...
Searching...
No Matches
drc_test_provider_creepage.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2024 KiCad Developers.
3 * Copyright (C) 2024 Fabien Corona f.corona<at>laposte.net
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, you may find one here:
17 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
18 * or you may search the http://www.gnu.org website for the version 2 license,
19 * or you may write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
21 */
22
23#include <common.h>
24#include <macros.h>
26#include <footprint.h>
27#include <pad.h>
28#include <pcb_track.h>
29#include <pcb_shape.h>
30#include <zone.h>
31#include <advanced_config.h>
32#include <geometry/shape_rect.h>
33#include <geometry/seg.h>
35#include <drc/drc_item.h>
36#include <drc/drc_rule.h>
39
41
42
43/*
44 Physical creepage tests.
45
46 Errors generated:
47 - DRCE_CREEPAGE
48 */
49
51{
52public:
54
56
57 virtual bool Run() override;
58
59 virtual const wxString GetName() const override { return wxT( "creepage" ); };
60
61 virtual const wxString GetDescription() const override { return wxT( "Tests creepage" ); }
62
63 double GetMaxConstraint( const std::vector<int>& aNetCodes );
64
65private:
66 int testCreepage();
67 int testCreepage( CreepageGraph& aGraph, int aNetCodeA, int aNetCodeB, PCB_LAYER_ID aLayer );
68
69 void CollectBoardEdges( std::vector<BOARD_ITEM*>& aVector );
70 void CollectNetCodes( std::vector<int>& aVector );
71};
72
73
75{
76 if( !ADVANCED_CFG::GetCfg().m_EnableCreepageDRC )
77 {
78 return true;
79 }
80
82
83 //int errorMax = m_board->GetDesignSettings().m_MaxError;
84
86 {
87 if( !reportPhase( _( "Checking creepage..." ) ) )
88 return false; // DRC cancelled
89
91 }
92 return !m_drcEngine->IsCancelled();
93}
94
95
96std::shared_ptr<GraphNode> FindInGraphNodes( std::shared_ptr<GraphNode> aNode,
97 std::vector<std::shared_ptr<GraphNode>>& aGraph )
98{
99 if( !aNode )
100 return nullptr;
101
102 for( std::shared_ptr<GraphNode> gn : aGraph )
103 {
104 if( aNode->m_pos == gn->m_pos )
105 {
106 return gn;
107 }
108 }
109 return nullptr;
110}
111
112
113int DRC_TEST_PROVIDER_CREEPAGE::testCreepage( CreepageGraph& aGraph, int aNetCodeA, int aNetCodeB,
114 PCB_LAYER_ID aLayer )
115{
116 PCB_TRACK bci1( m_board );
117 PCB_TRACK bci2( m_board );
118 bci1.SetNetCode( aNetCodeA );
119 bci2.SetNetCode( aNetCodeB );
120 bci1.SetLayer( aLayer );
121 bci2.SetLayer( aLayer );
122
123
124 DRC_CONSTRAINT constraint;
125 constraint = m_drcEngine->EvalRules( CREEPAGE_CONSTRAINT, &bci1, &bci2, aLayer );
126 double creepageValue = constraint.Value().Min();
127 aGraph.SetTarget( creepageValue );
128
129 if( creepageValue <= 0 )
130 return 0;
131
132 // Let's make a quick "clearance test"
133 NETINFO_ITEM* netA = m_board->FindNet( aNetCodeA );
134 NETINFO_ITEM* netB = m_board->FindNet( aNetCodeB );
135
136 if ( !netA || !netB )
137 return 0;
138
139 if ( netA->GetBoundingBox().Distance( netB->GetBoundingBox() ) > creepageValue )
140 return 0;
141
142 std::shared_ptr<GraphNode> NetA = aGraph.AddNetElements( aNetCodeA, aLayer, creepageValue );
143 std::shared_ptr<GraphNode> NetB = aGraph.AddNetElements( aNetCodeB, aLayer, creepageValue );
144
145
146 aGraph.GeneratePaths( creepageValue, aLayer );
147
148 std::vector<std::shared_ptr<GraphNode>> nodes1 = aGraph.m_nodes;
149 std::vector<std::shared_ptr<GraphNode>> nodes2 = aGraph.m_nodes;
150
151 alg::for_all_pairs( aGraph.m_nodes.begin(), aGraph.m_nodes.end(),
152 [&]( std::shared_ptr<GraphNode> aN1, std::shared_ptr<GraphNode> aN2 )
153 {
154 if( aN1 == aN2 )
155 return;
156
157 if( !aN1 || !aN2 )
158 return;
159
160 if( !( aN1->m_parent ) || !( aN2->m_parent ) )
161 return;
162
163 if( ( aN1->m_parent ) != ( aN2->m_parent ) )
164 return;
165
166
167 if( aN1->m_parent->IsConductive() )
168 return;
169
170 if( aN1->m_connectDirectly || aN2->m_connectDirectly )
171 return;
172
173 // We are only looking for points on circles and arcs
174
175 if( aN1->m_type != GraphNode::POINT )
176 return;
177
178 if( aN2->m_type != GraphNode::POINT )
179 return;
180
181 aN1->m_parent->ConnectChildren( aN1, aN2, aGraph );
182 } );
183
184 std::vector<std::shared_ptr<GraphConnection>> shortestPath;
185 shortestPath.clear();
186 double distance = aGraph.Solve( NetA, NetB, shortestPath );
187
188
189 if( ( shortestPath.size() > 0 ) && ( distance - creepageValue < 0 ) )
190 {
191 std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_CREEPAGE );
192 wxString msg = formatMsg( _( "(%s creepage %s; actual %s)" ), constraint.GetName(),
193 creepageValue, distance );
194 drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
195 drce->SetViolatingRule( constraint.GetParentRule() );
196
197 if( shortestPath.size() >= 4 && shortestPath[1]->n1 && shortestPath[1]->n2 )
198 drce->SetItems( shortestPath[1]->n1->m_parent->GetParent(),
199 shortestPath[shortestPath.size() - 2]->n2->m_parent->GetParent() );
200
201 std::vector<PCB_SHAPE> shortestPathShapes1, shortestPathShapes2;
202
203 VECTOR2I startPoint = shortestPath[1]->m_path.a2;
204 VECTOR2I endPoint = shortestPath[shortestPath.size() - 2]->m_path.a2;
205
206 PCB_SHAPE s;
207 s.SetStart( startPoint );
208 s.SetEnd( endPoint );
209
210
211 std::vector<PCB_SHAPE> path;
212 for( std::shared_ptr<GraphConnection> gc : shortestPath )
213 {
214 if( !gc )
215 continue;
216
217 std::vector<PCB_SHAPE> shapes = gc->GetShapes();
218
219 for( PCB_SHAPE sh : shapes )
220 {
221 path.push_back( sh );
222 }
223 }
224
225 this->ShowPathDRC( path, startPoint, endPoint, distance );
226 reportViolation( drce, shortestPath[1]->m_path.a2, aLayer );
227 // After a ShowPathDRC() call, restore the handler
229 }
230 shortestPath.clear();
231
232 return 1;
233}
234
235double DRC_TEST_PROVIDER_CREEPAGE::GetMaxConstraint( const std::vector<int>& aNetCodes )
236{
237 double maxConstraint = 0;
238 DRC_CONSTRAINT constraint;
239
240 PCB_TRACK bci1( m_board );
241 PCB_TRACK bci2( m_board );
242
243
244 alg::for_all_pairs( aNetCodes.begin(), aNetCodes.end(),
245 [&]( int aNet1, int aNet2 )
246 {
247 if( aNet1 == aNet2 )
248 return;
249
250 bci1.SetNetCode( aNet1 );
251 bci2.SetNetCode( aNet2 );
252
253 for( PCB_LAYER_ID layer : LSET::AllCuMask().CuStack() )
254 {
255 bci1.SetLayer( layer );
256 bci2.SetLayer( layer );
257 constraint = m_drcEngine->EvalRules( CREEPAGE_CONSTRAINT, &bci1,
258 &bci2, layer );
259 double value = constraint.Value().Min();
260 maxConstraint = value > maxConstraint ? value : maxConstraint;
261 }
262 } );
263
264 return maxConstraint;
265}
266
267void DRC_TEST_PROVIDER_CREEPAGE::CollectNetCodes( std::vector<int>& aVector )
268{
269 NETCODES_MAP nets = m_board->GetNetInfo().NetsByNetcode();
270
271 for( auto it = nets.begin(); it != nets.end(); it++ )
272 {
273 aVector.push_back( it->first );
274 }
275}
276
277void DRC_TEST_PROVIDER_CREEPAGE::CollectBoardEdges( std::vector<BOARD_ITEM*>& aVector )
278{
279 if( !m_board )
280 return;
281
282 for( BOARD_ITEM* drawing : m_board->Drawings() )
283 {
284 if( !drawing )
285 continue;
286
287 if( drawing->IsOnLayer( Edge_Cuts ) )
288 {
289 aVector.push_back( drawing );
290 }
291 }
292
293 for( FOOTPRINT* fp : m_board->Footprints() )
294 {
295 if( !fp )
296 continue;
297
298 for( BOARD_ITEM* drawing : fp->GraphicalItems() )
299 {
300 if( !drawing )
301 continue;
302
303 if( drawing->IsOnLayer( Edge_Cuts ) )
304 {
305 aVector.push_back( drawing );
306 }
307 }
308 }
309
310 for( const PAD* p : m_board->GetPads() )
311 {
312 if( !p )
313 continue;
314
315
316 if( p->GetAttribute() != PAD_ATTRIB::NPTH )
317 continue;
318
319 PCB_SHAPE* s = new PCB_SHAPE( NULL, SHAPE_T::CIRCLE );
320 s->SetRadius( p->GetDrillSize().x / 2 );
321 s->SetPosition( p->GetPosition() );
322 aVector.push_back( s );
323 }
324}
325
327{
328 if( !m_board )
329 return -1;
330
331 std::vector<int> netcodes;
332
333 this->CollectNetCodes( netcodes );
334 double maxConstraint = GetMaxConstraint( netcodes );
335
336 if( maxConstraint <= 0 )
337 return 0;
338
339 SHAPE_POLY_SET outline;
340
341 if( !m_board->GetBoardPolygonOutlines( outline ) )
342 return -1;
343
344 const DRAWINGS drawings = m_board->Drawings();
345 CreepageGraph graph( *m_board );
347 graph.m_boardOutline = &outline;
348
349 this->CollectBoardEdges( graph.m_boardEdge );
353
354 graph.GeneratePaths( maxConstraint, Edge_Cuts );
355
356
357 int beNodeSize = graph.m_nodes.size();
358 int beConnectionsSize = graph.m_connections.size();
359 bool prevTestChangedGraph = false;
360
361 alg::for_all_pairs( netcodes.begin(), netcodes.end(),
362 [&]( int aNet1, int aNet2 )
363 {
364 if( aNet1 == aNet2 )
365 return;
366
367 for( PCB_LAYER_ID layer : LSET::AllCuMask().CuStack() )
368 {
369 if( !m_board->IsLayerEnabled( layer ) )
370 continue;
371
372 if ( prevTestChangedGraph )
373 {
374 size_t vectorSize = graph.m_connections.size();
375
376 for( size_t i = beConnectionsSize; i < vectorSize; i++ )
377 {
378 // We need to remove the connection from its endpoints' lists.
379 graph.RemoveConnection( graph.m_connections[i], false );
380 }
381 graph.m_connections.resize( beConnectionsSize, nullptr );
382
383 vectorSize = graph.m_nodes.size();
384 graph.m_nodes.resize( beNodeSize, nullptr );
385 }
386
387 prevTestChangedGraph = testCreepage( graph, aNet1, aNet2, layer );
388 }
389 } );
390
391 return 1;
392}
393
394
395namespace detail
396{
398}
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
bool SetNetCode(int aNetCode, bool aNoAssert)
Set net using a net code.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:79
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:288
bool GetBoardPolygonOutlines(SHAPE_POLY_SET &aOutlines, OUTLINE_ERROR_HANDLER *aErrorHandler=nullptr, bool aAllowUseArcsInPolygons=false, bool aIncludeNPTHAsOutlines=false)
Extract the board outlines and build a closed polygon from lines, arcs and circle items on edge cut l...
Definition: board.cpp:2491
const NETINFO_LIST & GetNetInfo() const
Definition: board.h:871
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition: board.cpp:1916
const std::vector< PAD * > GetPads() const
Return a reference to a list of all the pads.
Definition: board.cpp:2594
const FOOTPRINTS & Footprints() const
Definition: board.h:331
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:890
const DRAWINGS & Drawings() const
Definition: board.h:333
ecoord_type Distance(const Vec &aP) const
Definition: box2.h:797
A graph with nodes and connections for creepage calculation.
std::vector< CREEP_SHAPE * > m_shapeCollection
std::vector< std::shared_ptr< GraphNode > > m_nodes
std::shared_ptr< GraphNode > AddNetElements(int aNetCode, PCB_LAYER_ID aLayer, int aMaxCreepage)
std::vector< std::shared_ptr< GraphConnection > > m_connections
void SetTarget(double aTarget)
void TransformCreepShapesToNodes(std::vector< CREEP_SHAPE * > &aShapes)
double Solve(std::shared_ptr< GraphNode > &aFrom, std::shared_ptr< GraphNode > &aTo, std::vector< std::shared_ptr< GraphConnection > > &aResult)
std::vector< BOARD_ITEM * > m_boardEdge
void TransformEdgeToCreepShapes()
void GeneratePaths(double aMaxWeight, PCB_LAYER_ID aLayer, bool aGenerateBoardEdges=true)
SHAPE_POLY_SET * m_boardOutline
wxString GetName() const
Definition: drc_rule.h:159
MINOPTMAX< int > & Value()
Definition: drc_rule.h:152
DRC_RULE * GetParentRule() const
Definition: drc_rule.h:155
BOARD * GetBoard() const
Definition: drc_engine.h:99
bool IsErrorLimitExceeded(int error_code)
DRC_CONSTRAINT EvalRules(DRC_CONSTRAINT_T aConstraintType, const BOARD_ITEM *a, const BOARD_ITEM *b, PCB_LAYER_ID aLayer, REPORTER *aReporter=nullptr)
Definition: drc_engine.cpp:679
bool IsCancelled() const
DRC_GRAPHICS_HANDLER m_graphicsHandler
Definition: drc_engine.h:276
static std::shared_ptr< DRC_ITEM > Create(int aErrorCode)
Constructs a DRC_ITEM for the given error code.
Definition: drc_item.cpp:372
void ShowPathDRC(const std::vector< PCB_SHAPE > &aShapes, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aLength)
void CollectBoardEdges(std::vector< BOARD_ITEM * > &aVector)
double GetMaxConstraint(const std::vector< int > &aNetCodes)
virtual const wxString GetName() const override
virtual const wxString GetDescription() const override
virtual bool Run() override
Run this provider against the given PCB with configured options (if any).
void CollectNetCodes(std::vector< int > &aVector)
wxString formatMsg(const wxString &aFormatString, const wxString &aSource, double aConstraint, double aActual)
virtual bool reportPhase(const wxString &aStageName)
virtual void reportViolation(std::shared_ptr< DRC_ITEM > &item, const VECTOR2I &aMarkerPos, int aMarkerLayer)
DRC_ENGINE * m_drcEngine
void SetRadius(int aX)
Definition: eda_shape.h:189
void SetStart(const VECTOR2I &aStart)
Definition: eda_shape.h:134
void SetEnd(const VECTOR2I &aEnd)
Definition: eda_shape.h:171
T Min() const
Definition: minoptmax.h:33
Handle the data for a net.
Definition: netinfo.h:56
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
const NETCODES_MAP & NetsByNetcode() const
Return the netcode map, at least for python.
Definition: netinfo.h:375
Definition: pad.h:54
void SetPosition(const VECTOR2I &aPos) override
Definition: pcb_shape.h:76
Represent a set of closed polygons.
The common library.
@ DRCE_CREEPAGE
Definition: drc_item.h:44
@ CREEPAGE_CONSTRAINT
Definition: drc_rule.h:50
std::shared_ptr< GraphNode > FindInGraphNodes(std::shared_ptr< GraphNode > aNode, std::vector< std::shared_ptr< GraphNode > > &aGraph)
#define _(s)
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ Edge_Cuts
Definition: layer_ids.h:112
This file contains miscellaneous commonly used macros and functions.
void for_all_pairs(_InputIterator __first, _InputIterator __last, _Function __f)
Apply a function to every possible pair of elements of a sequence.
Definition: kicad_algo.h:84
static DRC_REGISTER_TEST_PROVIDER< DRC_TEST_PROVIDER_ANNULAR_WIDTH > dummy
static float distance(const SFVEC2UI &a, const SFVEC2UI &b)