KiCad PCB EDA Suite
drc_test_provider_courtyard_clearance.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 (C) 2004-2020 KiCad Developers.
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 #include <drc/drc_item.h>
26 #include <drc/drc_rule.h>
28 
29 /*
30  Couartyard clearance. Tests for malformed component courtyards and overlapping footprints.
31  Generated errors:
32  - DRCE_OVERLAPPING_FOOTPRINTS
33  - DRCE_MISSING_COURTYARD
34  - DRCE_MALFORMED_COURTYARD
35 
36  TODO: do an actual clearance check instead of polygon intersection. Treat closed outlines
37  as filled and allow open curves in the courtyard.
38 */
39 
41 {
42 public:
44  {
45  m_isRuleDriven = false;
46  }
47 
49  {
50  }
51 
52  virtual bool Run() override;
53 
54  virtual const wxString GetName() const override
55  {
56  return "courtyard_clearance";
57  }
58 
59  virtual const wxString GetDescription() const override
60  {
61  return "Tests footprints' courtyard clearance";
62  }
63 
64  virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override;
65 
66  int GetNumPhases() const override;
67 
68 private:
70 
72 };
73 
74 
76 {
77  const int delta = 100; // This is the number of tests between 2 calls to the progress bar
78 
79  // Detects missing (or malformed) footprint courtyards
80  if( !reportPhase( _( "Checking footprint courtyard definitions..." ) ) )
81  return;
82 
83  int ii = 0;
84 
85  for( FOOTPRINT* footprint : m_board->Footprints() )
86  {
87  if( !reportProgress( ii++, m_board->Footprints().size(), delta ) )
88  return;
89 
90  if( ( footprint->GetFlags() & MALFORMED_COURTYARDS ) != 0 )
91  {
93  continue;
94 
95  OUTLINE_ERROR_HANDLER errorHandler =
96  [&]( const wxString& msg, BOARD_ITEM* , BOARD_ITEM* , const wxPoint& pt )
97  {
98  std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_MALFORMED_COURTYARD );
99  drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + msg );
100  drcItem->SetItems( footprint );
101  reportViolation( drcItem, pt );
102  };
103 
104  // Re-run courtyard tests to generate DRC_ITEMs
105  footprint->BuildPolyCourtyards( &errorHandler );
106  }
107  else if( footprint->GetPolyCourtyardFront().OutlineCount() == 0
108  && footprint->GetPolyCourtyardBack().OutlineCount() == 0 )
109  {
111  continue;
112 
113  std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_MISSING_COURTYARD );
114  drcItem->SetItems( footprint );
115  reportViolation( drcItem, footprint->GetPosition() );
116  }
117  else
118  {
119  footprint->GetPolyCourtyardFront().BuildBBoxCaches();
120  footprint->GetPolyCourtyardBack().BuildBBoxCaches();
121  }
122  }
123 }
124 
125 
127 {
128  const int delta = 100; // This is the number of tests between 2 calls to the progress bar
129 
130  if( !reportPhase( _( "Checking footprints for overlapping courtyards..." ) ) )
131  return;
132 
133  int ii = 0;
134 
135  for( auto it1 = m_board->Footprints().begin(); it1 != m_board->Footprints().end(); it1++ )
136  {
137  if( !reportProgress( ii++, m_board->Footprints().size(), delta ) )
138  break;
139 
141  break;
142 
143  FOOTPRINT* footprint = *it1;
144  const SHAPE_POLY_SET& footprintFront = footprint->GetPolyCourtyardFront();
145  const SHAPE_POLY_SET& footprintBack = footprint->GetPolyCourtyardBack();
146 
147  if( footprintFront.OutlineCount() == 0 && footprintBack.OutlineCount() == 0 )
148  continue; // No courtyards defined
149 
150  BOX2I frontBBox = footprintFront.BBoxFromCaches();
151  BOX2I backBBox = footprintBack.BBoxFromCaches();
152 
153  frontBBox.Inflate( m_largestClearance );
154  backBBox.Inflate( m_largestClearance );
155 
156  for( auto it2 = it1 + 1; it2 != m_board->Footprints().end(); it2++ )
157  {
158  FOOTPRINT* test = *it2;
159  const SHAPE_POLY_SET& testFront = test->GetPolyCourtyardFront();
160  const SHAPE_POLY_SET& testBack = test->GetPolyCourtyardBack();
161  DRC_CONSTRAINT constraint;
162  int clearance;
163  int actual;
164  VECTOR2I pos;
165 
166  if( footprintFront.OutlineCount() > 0 && testFront.OutlineCount() > 0
167  && frontBBox.Intersects( testFront.BBoxFromCaches() ) )
168  {
169  constraint = m_drcEngine->EvalRules( COURTYARD_CLEARANCE_CONSTRAINT, footprint,
170  test, F_Cu );
171  clearance = constraint.GetValue().Min();
172 
173  if( clearance >= 0 && footprintFront.Collide( &testFront, clearance, &actual, &pos ) )
174  {
175  std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_OVERLAPPING_FOOTPRINTS );
176 
177  if( clearance > 0 )
178  {
179  m_msg.Printf( _( "(%s clearance %s; actual %s)" ),
180  constraint.GetName(),
181  MessageTextFromValue( userUnits(), clearance ),
182  MessageTextFromValue( userUnits(), actual ) );
183 
184  drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + m_msg );
185  drce->SetViolatingRule( constraint.GetParentRule() );
186  }
187 
188  drce->SetItems( footprint, test );
189  reportViolation( drce, (wxPoint) pos );
190  }
191  }
192 
193  if( footprintBack.OutlineCount() > 0 && testBack.OutlineCount() > 0
194  && backBBox.Intersects( testBack.BBoxFromCaches() ) )
195  {
196  constraint = m_drcEngine->EvalRules( COURTYARD_CLEARANCE_CONSTRAINT, footprint,
197  test, B_Cu );
198  clearance = constraint.GetValue().Min();
199 
200  if( clearance >= 0 && footprintBack.Collide( &testBack, clearance, &actual, &pos ) )
201  {
202  std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_OVERLAPPING_FOOTPRINTS );
203 
204  if( clearance > 0 )
205  {
206  m_msg.Printf( _( "(%s clearance %s; actual %s)" ),
207  constraint.GetName(),
208  MessageTextFromValue( userUnits(), clearance ),
209  MessageTextFromValue( userUnits(), actual ) );
210 
211  drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + m_msg );
212  drce->SetViolatingRule( constraint.GetParentRule() );
213  }
214 
215  drce->SetItems( footprint, test );
216  reportViolation( drce, (wxPoint) pos );
217  }
218  }
219  }
220  }
221 }
222 
223 
225 {
227  DRC_CONSTRAINT constraint;
228 
230  m_largestClearance = constraint.GetValue().Min();
231 
232  reportAux( "Worst courtyard clearance : %d nm", m_largestClearance );
233 
235 
237 
238  return true;
239 }
240 
241 
243 {
244  return 2;
245 }
246 
247 
249 {
251 }
252 
253 
254 namespace detail
255 {
257 }
wxString MessageTextFromValue(EDA_UNITS aUnits, int aValue, bool aAddUnitLabel, EDA_DATA_TYPE aType)
Convert a value to a string using double notation.
Definition: base_units.cpp:125
const SHAPE_POLY_SET & GetPolyCourtyardFront() const
Used in DRC to test the courtyard area (a complex polygon).
Definition: footprint.h:648
int OutlineCount() const
Return the number of vertices in a given outline/hole.
static std::shared_ptr< DRC_ITEM > Create(int aErrorCode)
Constructs a DRC_ITEM for the given error code.
Definition: drc_item.cpp:245
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:82
const BOX2I BBoxFromCaches() const
static DRC_REGISTER_TEST_PROVIDER< DRC_TEST_PROVIDER_ANNULUS > dummy
bool IsErrorLimitExceeded(int error_code)
virtual bool Run() override
Runs this provider against the given PCB with configured options (if any).
virtual bool reportProgress(int aCount, int aSize, int aDelta)
T Min() const
Definition: minoptmax.h:33
wxString GetName() const
Definition: drc_rule.h:127
bool Intersects(const BOX2< Vec > &aRect) const
Function Intersects.
Definition: box2.h:236
DRC_RULE * GetParentRule() const
Definition: drc_rule.h:125
bool QueryWorstConstraint(DRC_CONSTRAINT_T aRuleId, DRC_CONSTRAINT &aConstraint)
BOARD * GetBoard() const
Definition: drc_engine.h:87
virtual bool reportPhase(const wxString &aStageName)
Represent a set of closed polygons.
FOOTPRINTS & Footprints()
Definition: board.h:296
const SHAPE_POLY_SET & GetPolyCourtyardBack() const
Definition: footprint.h:649
#define MALFORMED_COURTYARDS
Definition: eda_item.h:125
EDA_UNITS userUnits() const
DRC_CONSTRAINT EvalRules(DRC_CONSTRAINT_T aConstraintId, const BOARD_ITEM *a, const BOARD_ITEM *b, PCB_LAYER_ID aLayer, REPORTER *aReporter=nullptr)
Definition: drc_engine.cpp:715
virtual std::set< DRC_CONSTRAINT_T > GetConstraintTypes() const override
bool Collide(const SHAPE *aShape, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if the boundary of shape (this) lies closer to the shape aShape than aClearance,...
virtual void reportViolation(std::shared_ptr< DRC_ITEM > &item, wxPoint aMarkerPos)
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Function Inflate inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:302
const MINOPTMAX< int > & GetValue() const
Definition: drc_rule.h:121
virtual const wxString GetDescription() const override
#define _(s)
Definition: 3d_actions.cpp:33
DRC_ENGINE * m_drcEngine
const std::function< void(const wxString &msg, BOARD_ITEM *itemA, BOARD_ITEM *itemB, const wxPoint &pt)> OUTLINE_ERROR_HANDLER
virtual void reportAux(wxString fmt,...)