KiCad PCB EDA Suite
Loading...
Searching...
No Matches
drc_interactive_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-2022 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_engine.h>
26#include <drc/drc_item.h>
27#include <drc/drc_rule.h>
28#include <pad.h>
29#include <zone.h>
31#include <footprint.h>
32
34{
35 std::vector<BOX2I> fpBBBoxes( m_FpInMove.size() );
36 BOX2I movingBBox;
37
38 for( size_t i = 0; i < m_FpInMove.size(); i++ )
39 {
40 FOOTPRINT* fpB = m_FpInMove[i];
41
42 BOX2I bbox = fpB->GetBoundingBox( true );
43 movingBBox.Merge( bbox );
44 fpBBBoxes[i] = bbox;
45 }
46
48
49 for( FOOTPRINT* fpA: m_board->Footprints() )
50 {
51 if( fpA->IsSelected() )
52 continue;
53
54 BOX2I fpABBox = fpA->GetBoundingBox( true );
55
56 if( !movingBBox.Intersects( fpABBox ) )
57 continue;
58
59 const SHAPE_POLY_SET& frontA = fpA->GetCourtyard( F_CrtYd );
60 const SHAPE_POLY_SET& backA = fpA->GetCourtyard( B_CrtYd );
61
62 if( frontA.OutlineCount() == 0 && backA.OutlineCount() == 0 )
63 // No courtyards defined and no hole testing against other footprint's courtyards
64 continue;
65
66 BOX2I frontABBox = frontA.BBoxFromCaches();
67 BOX2I backABBox = backA.BBoxFromCaches();
68
71
72 for( size_t inMoveId = 0; inMoveId < m_FpInMove.size(); inMoveId++ )
73 {
74 FOOTPRINT* fpB = m_FpInMove[inMoveId];
75 const SHAPE_POLY_SET& frontB = fpB->GetCourtyard( F_CrtYd );
76 const SHAPE_POLY_SET& backB = fpB->GetCourtyard( B_CrtYd );
77
78 const BOX2I fpBBBox = fpBBBoxes[inMoveId];
79 const BOX2I frontBBBox = frontB.BBoxFromCaches();
80 const BOX2I backBBBox = backB.BBoxFromCaches();
81
82 int clearance;
83 int actual;
84 VECTOR2I pos;
85
86 if( frontA.OutlineCount() > 0 && frontB.OutlineCount() > 0
87 && frontABBox.Intersects( frontBBBox ) )
88 {
89 // Currently, do not use DRC engine for calculation time reasons
90 // DRC_CONSTRAINT constraint = m_drcEngine->EvalRules( COURTYARD_CLEARANCE_CONSTRAINT, fpA, fpB, B_Cu );
91 // constraint.GetValue().Min();
92 clearance = 0;
93
94 if( frontA.Collide( &frontB, clearance, &actual, &pos ) )
95 {
96 m_itemsInConflict.insert( fpA );
97 m_itemsInConflict.insert( fpB );
98 }
99 }
100
101 if( backA.OutlineCount() > 0 && backB.OutlineCount() > 0
102 && backABBox.Intersects( backBBBox ) )
103 {
104 // Currently, do not use DRC engine for calculation time reasons
105 // DRC_CONSTRAINT constraint = m_drcEngine->EvalRules( COURTYARD_CLEARANCE_CONSTRAINT, fpA, fpB, B_Cu );
106 // constraint.GetValue().Min();
107 clearance = 0;
108
109 if( backA.Collide( &backB, clearance, &actual, &pos ) )
110 {
111 m_itemsInConflict.insert( fpA );
112 m_itemsInConflict.insert( fpB );
113 }
114 }
115
116 // Now test if a pad hole of some other footprint is inside the courtyard area
117 // of the moved footprint
118 auto testPadAgainstCourtyards =
119 [&]( const PAD* pad, FOOTPRINT* footprint ) -> bool
120 {
121 if( pad->HasHole() )
122 {
123 std::shared_ptr<SHAPE_SEGMENT> hole = pad->GetEffectiveHoleShape();
124 const SHAPE_POLY_SET& front = footprint->GetCachedCourtyard( F_CrtYd );
125 const SHAPE_POLY_SET& back = footprint->GetCachedCourtyard( B_CrtYd );
126
127 if( front.OutlineCount() > 0 && front.Collide( hole.get(), 0 ) )
128 return true;
129 else if( back.OutlineCount() > 0 && back.Collide( hole.get(), 0 ) )
130 return true;
131 }
132
133 return false;
134 };
135
136 bool skipNextCmp = false;
137
138 if( ( frontA.OutlineCount() > 0 && frontABBox.Intersects( fpBBBox ) )
139 || ( backA.OutlineCount() > 0 && backABBox.Intersects( fpBBBox ) ) )
140 {
141 for( const PAD* padB : fpB->Pads() )
142 {
143 if( testPadAgainstCourtyards( padB, fpA ) )
144 {
145 m_itemsInConflict.insert( fpA );
146 m_itemsInConflict.insert( fpB );
147 skipNextCmp = true;
148 break;
149 }
150 }
151 }
152
153 if( skipNextCmp )
154 continue; // fpA and fpB are already in list
155
156 if( ( frontB.OutlineCount() > 0 && frontBBBox.Intersects( fpABBox ) )
157 || ( backB.OutlineCount() > 0 && backBBBox.Intersects( fpABBox ) ) )
158 {
159 for( const PAD* padA : fpA->Pads() )
160 {
161 if( testPadAgainstCourtyards( padA, fpB ) )
162 {
163 m_itemsInConflict.insert( fpA );
164 m_itemsInConflict.insert( fpB );
165 break;
166 }
167 }
168 }
169 }
170 }
171
172 for( ZONE* zone : m_board->Zones() )
173 {
174 if( !zone->GetIsRuleArea() || !zone->HasKeepoutParametersSet()
175 || !zone->GetDoNotAllowFootprints() )
176 {
177 continue;
178 }
179
180 bool disallowFront = ( zone->GetLayerSet() & LSET::FrontMask() ).any();
181 bool disallowBack = ( zone->GetLayerSet() & LSET::BackMask() ).any();
182
183 for( FOOTPRINT* fp : m_FpInMove )
184 {
185 if( disallowFront )
186 {
187 const SHAPE_POLY_SET& frontCourtyard = fp->GetCourtyard( F_CrtYd );
188
189 if( !frontCourtyard.IsEmpty() )
190 {
191 if( zone->Outline()->Collide( &frontCourtyard.Outline( 0 ) ) )
192 {
193 m_itemsInConflict.insert( fp );
194 m_itemsInConflict.insert( zone );
195 break;
196 }
197 }
198 }
199
200 if( disallowBack )
201 {
202 const SHAPE_POLY_SET& backCourtyard = fp->GetCourtyard( B_CrtYd );
203
204 if( !backCourtyard.IsEmpty() )
205 {
206 if( zone->Outline()->Collide( &backCourtyard.Outline( 0 ) ) )
207 {
208 m_itemsInConflict.insert( fp );
209 m_itemsInConflict.insert( zone );
210 break;
211 }
212 }
213 }
214 }
215 }
216}
217
218
220{
221 m_board = aBoard;
222
223 // Update courtyard data and clear the COURTYARD_CONFLICT flag
224 for( FOOTPRINT* fp: m_board->Footprints() )
225 {
227 fp->BuildCourtyardCaches();
228 }
229}
230
231
233{
234 m_itemsInConflict.clear();
236
237 DRC_CONSTRAINT constraint;
238
241
243
244 return true;
245}
246
247
249 bool aHighlightMoved )
250{
251 // Ensure the "old" conflicts are cleared
253 {
254 item->ClearFlags(COURTYARD_CONFLICT );
255 aView->Update( item );
257 }
258
259 m_lastItemsInConflict.clear();
260
261 for( BOARD_ITEM* item: m_itemsInConflict )
262 {
263 if( aHighlightMoved || !alg::contains( m_FpInMove, item ) )
264 {
265 if( !item->HasFlag( COURTYARD_CONFLICT ) )
266 {
267 item->SetFlags( COURTYARD_CONFLICT );
268 aView->Update( item );
270 }
271
272 m_lastItemsInConflict.push_back( item );
273 }
274 }
275}
276
277
279{
281 {
282 item->ClearFlags( COURTYARD_CONFLICT );
283 aView->Update( item );
285 }
286}
287
288
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:79
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:290
const ZONES & Zones() const
Definition: board.h:335
const FOOTPRINTS & Footprints() const
Definition: board.h:331
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:558
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition: box2.h:658
constexpr bool Intersects(const BOX2< Vec > &aRect) const
Definition: box2.h:311
const MINOPTMAX< int > & GetValue() const
Definition: drc_rule.h:152
bool QueryWorstConstraint(DRC_CONSTRAINT_T aRuleId, DRC_CONSTRAINT &aConstraint)
virtual bool Run() override
Run this provider against the given PCB with configured options (if any).
void UpdateConflicts(KIGFX::VIEW *aView, bool aHighlightMoved)
DRC_ENGINE * m_drcEngine
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: eda_item.h:129
std::deque< PAD * > & Pads()
Definition: footprint.h:206
const SHAPE_POLY_SET & GetCourtyard(PCB_LAYER_ID aLayer) const
Used in DRC to test the courtyard area (a complex polygon).
Definition: footprint.cpp:2891
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: footprint.cpp:1294
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:68
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
Definition: view.cpp:1669
void MarkTargetDirty(int aTarget)
Set or clear target 'dirty' flag.
Definition: view.h:636
static LSET FrontMask()
Return a mask holding all technical layers and the external CU layer on front side.
Definition: lset.cpp:772
static LSET BackMask()
Return a mask holding all technical layers and the external CU layer on back side.
Definition: lset.cpp:779
T Min() const
Definition: minoptmax.h:33
Definition: pad.h:54
Represent a set of closed polygons.
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
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,...
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
int OutlineCount() const
Return the number of outlines in the set.
const BOX2I BBoxFromCaches() const
Handle a list of polygons defining a copper zone.
Definition: zone.h:73
@ COURTYARD_CLEARANCE_CONSTRAINT
Definition: drc_rule.h:55
#define COURTYARD_CONFLICT
temporary set when moving footprints having courtyard overlapping
@ F_CrtYd
Definition: layer_ids.h:116
@ B_CrtYd
Definition: layer_ids.h:115
@ TARGET_OVERLAY
Items that may change while the view stays the same (noncached)
Definition: definitions.h:39
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition: kicad_algo.h:100