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 The 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 {
226 fp->ClearFlags( COURTYARD_CONFLICT );
227 fp->BuildCourtyardCaches();
228 }
229}
230
231
233{
234 m_itemsInConflict.clear();
236
237 DRC_CONSTRAINT constraint;
238
239 if( m_drcEngine->QueryWorstConstraint( COURTYARD_CLEARANCE_CONSTRAINT, constraint ) )
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
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
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:317
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:162
virtual bool Run() override
Run this provider against the given PCB with configured options (if any).
void UpdateConflicts(KIGFX::VIEW *aView, bool aHighlightMoved)
std::deque< PAD * > & Pads()
Definition footprint.h:224
const SHAPE_POLY_SET & GetCourtyard(PCB_LAYER_ID aLayer) const
Used in DRC to test the courtyard area (a complex polygon).
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:66
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:1685
void MarkTargetDirty(int aTarget)
Set or clear target 'dirty' flag.
Definition view.h:639
static const LSET & FrontMask()
Return a mask holding all technical layers and the external CU layer on front side.
Definition lset.cpp:705
static const LSET & BackMask()
Return a mask holding all technical layers and the external CU layer on back side.
Definition lset.cpp:712
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:74
@ 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
int clearance
int actual
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695