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, see <https://www.gnu.org/licenses/>.
18 */
19
21#include <drc/drc_engine.h>
22#include <drc/drc_item.h>
23#include <drc/drc_rule.h>
24#include <pad.h>
25#include <zone.h>
27#include <footprint.h>
28#include <view/view.h>
29
31{
32 std::vector<BOX2I> fpBBBoxes( m_FpInMove.size() );
33 BOX2I movingBBox;
34
35 for( size_t i = 0; i < m_FpInMove.size(); i++ )
36 {
37 FOOTPRINT* fpB = m_FpInMove[i];
38
39 BOX2I bbox = fpB->GetBoundingBox( true );
40 movingBBox.Merge( bbox );
41 fpBBBoxes[i] = bbox;
42 }
43
45
46 for( FOOTPRINT* fpA: m_board->Footprints() )
47 {
48 if( fpA->IsSelected() )
49 continue;
50
51 BOX2I fpABBox = fpA->GetBoundingBox( true );
52
53 if( !movingBBox.Intersects( fpABBox ) )
54 continue;
55
56 const SHAPE_POLY_SET& frontA = fpA->GetCourtyard( F_CrtYd );
57 const SHAPE_POLY_SET& backA = fpA->GetCourtyard( B_CrtYd );
58
59 if( frontA.OutlineCount() == 0 && backA.OutlineCount() == 0 )
60 // No courtyards defined and no hole testing against other footprint's courtyards
61 continue;
62
63 BOX2I frontABBox = frontA.BBoxFromCaches();
64 BOX2I backABBox = backA.BBoxFromCaches();
65
68
69 for( size_t inMoveId = 0; inMoveId < m_FpInMove.size(); inMoveId++ )
70 {
71 FOOTPRINT* fpB = m_FpInMove[inMoveId];
72 const SHAPE_POLY_SET& frontB = fpB->GetCourtyard( F_CrtYd );
73 const SHAPE_POLY_SET& backB = fpB->GetCourtyard( B_CrtYd );
74
75 const BOX2I fpBBBox = fpBBBoxes[inMoveId];
76 const BOX2I frontBBBox = frontB.BBoxFromCaches();
77 const BOX2I backBBBox = backB.BBoxFromCaches();
78
79 int clearance;
80 int actual;
81 VECTOR2I pos;
82
83 if( frontA.OutlineCount() > 0 && frontB.OutlineCount() > 0
84 && frontABBox.Intersects( frontBBBox ) )
85 {
86 // Currently, do not use DRC engine for calculation time reasons
87 // DRC_CONSTRAINT constraint = m_drcEngine->EvalRules( COURTYARD_CLEARANCE_CONSTRAINT, fpA, fpB, B_Cu );
88 // constraint.GetValue().Min();
89 clearance = 0;
90
91 if( frontA.Collide( &frontB, clearance, &actual, &pos ) )
92 {
93 m_itemsInConflict.insert( fpA );
94 m_itemsInConflict.insert( fpB );
95 }
96 }
97
98 if( backA.OutlineCount() > 0 && backB.OutlineCount() > 0
99 && backABBox.Intersects( backBBBox ) )
100 {
101 // Currently, do not use DRC engine for calculation time reasons
102 // DRC_CONSTRAINT constraint = m_drcEngine->EvalRules( COURTYARD_CLEARANCE_CONSTRAINT, fpA, fpB, B_Cu );
103 // constraint.GetValue().Min();
104 clearance = 0;
105
106 if( backA.Collide( &backB, clearance, &actual, &pos ) )
107 {
108 m_itemsInConflict.insert( fpA );
109 m_itemsInConflict.insert( fpB );
110 }
111 }
112
113 // Now test if a pad hole of some other footprint is inside the courtyard area
114 // of the moved footprint
115 auto testPadAgainstCourtyards =
116 [&]( const PAD* pad, FOOTPRINT* footprint ) -> bool
117 {
118 if( pad->HasHole() )
119 {
120 std::shared_ptr<SHAPE_SEGMENT> hole = pad->GetEffectiveHoleShape();
121 const SHAPE_POLY_SET& front = footprint->GetCachedCourtyard( F_CrtYd );
122 const SHAPE_POLY_SET& back = footprint->GetCachedCourtyard( B_CrtYd );
123
124 if( front.OutlineCount() > 0 && front.Collide( hole.get(), 0 ) )
125 return true;
126 else if( back.OutlineCount() > 0 && back.Collide( hole.get(), 0 ) )
127 return true;
128 }
129
130 return false;
131 };
132
133 bool skipNextCmp = false;
134
135 if( ( frontA.OutlineCount() > 0 && frontABBox.Intersects( fpBBBox ) )
136 || ( backA.OutlineCount() > 0 && backABBox.Intersects( fpBBBox ) ) )
137 {
138 for( const PAD* padB : fpB->Pads() )
139 {
140 if( testPadAgainstCourtyards( padB, fpA ) )
141 {
142 m_itemsInConflict.insert( fpA );
143 m_itemsInConflict.insert( fpB );
144 skipNextCmp = true;
145 break;
146 }
147 }
148 }
149
150 if( skipNextCmp )
151 continue; // fpA and fpB are already in list
152
153 if( ( frontB.OutlineCount() > 0 && frontBBBox.Intersects( fpABBox ) )
154 || ( backB.OutlineCount() > 0 && backBBBox.Intersects( fpABBox ) ) )
155 {
156 for( const PAD* padA : fpA->Pads() )
157 {
158 if( testPadAgainstCourtyards( padA, fpB ) )
159 {
160 m_itemsInConflict.insert( fpA );
161 m_itemsInConflict.insert( fpB );
162 break;
163 }
164 }
165 }
166 }
167 }
168
169 for( ZONE* zone : m_board->Zones() )
170 {
171 if( !zone->GetIsRuleArea() || !zone->HasKeepoutParametersSet()
172 || !zone->GetDoNotAllowFootprints() )
173 {
174 continue;
175 }
176
177 bool disallowFront = ( zone->GetLayerSet() & LSET::FrontMask() ).any();
178 bool disallowBack = ( zone->GetLayerSet() & LSET::BackMask() ).any();
179
180 // Don't use GetBoardOutline(). We know we're looking at a board zone, and copying the outline
181 // is too expensive for DRC.
182 SHAPE_POLY_SET* boardZoneOutline = zone->Outline();
183
184 for( FOOTPRINT* fp : m_FpInMove )
185 {
186 if( disallowFront )
187 {
188 const SHAPE_POLY_SET& frontCourtyard = fp->GetCourtyard( F_CrtYd );
189
190 if( !frontCourtyard.IsEmpty() )
191 {
192 if( boardZoneOutline->Collide( &frontCourtyard.Outline( 0 ) ) )
193 {
194 m_itemsInConflict.insert( fp );
195 m_itemsInConflict.insert( zone );
196 break;
197 }
198 }
199 }
200
201 if( disallowBack )
202 {
203 const SHAPE_POLY_SET& backCourtyard = fp->GetCourtyard( B_CrtYd );
204
205 if( !backCourtyard.IsEmpty() )
206 {
207 if( boardZoneOutline->Collide( &backCourtyard.Outline( 0 ) ) )
208 {
209 m_itemsInConflict.insert( fp );
210 m_itemsInConflict.insert( zone );
211 break;
212 }
213 }
214 }
215 }
216 }
217}
218
219
221{
222 m_board = aBoard;
223
224 // Update courtyard data and clear the COURTYARD_CONFLICT flag
225 for( FOOTPRINT* fp: m_board->Footprints() )
226 {
227 fp->ClearFlags( COURTYARD_CONFLICT );
228 fp->BuildCourtyardCaches();
229 }
230}
231
232
234{
235 m_itemsInConflict.clear();
237
238 DRC_CONSTRAINT constraint;
239
240 if( m_drcEngine->QueryWorstConstraint( COURTYARD_CLEARANCE_CONSTRAINT, constraint ) )
242
244
245 return true;
246}
247
248
250 bool aHighlightMoved )
251{
252 // Ensure the "old" conflicts are cleared
254 {
255 item->ClearFlags(COURTYARD_CONFLICT );
256 aView->Update( item, KIGFX::APPEARANCE );
258 }
259
260 m_lastItemsInConflict.clear();
261
262 for( BOARD_ITEM* item: m_itemsInConflict )
263 {
264 if( aHighlightMoved || !alg::contains( m_FpInMove, item ) )
265 {
266 if( !item->HasFlag( COURTYARD_CONFLICT ) )
267 {
268 item->SetFlags( COURTYARD_CONFLICT );
269 aView->Update( item, KIGFX::APPEARANCE );
271 }
272
273 m_lastItemsInConflict.push_back( item );
274 }
275 }
276}
277
278
280{
282 {
283 item->ClearFlags( COURTYARD_CONFLICT );
284 aView->Update( item );
286 }
287}
288
289
BOX2< VECTOR2I > BOX2I
Definition box2.h:927
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:84
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:409
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:553
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:653
constexpr bool Intersects(const BOX2< Vec > &aRect) const
Definition box2.h:308
const MINOPTMAX< int > & GetValue() const
Definition drc_rule.h:200
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:404
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:63
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:1852
void MarkTargetDirty(int aTarget)
Set or clear target 'dirty' flag.
Definition view.h:659
static const LSET & FrontMask()
Return a mask holding all technical layers and the external CU layer on front side.
Definition lset.cpp:718
static const LSET & BackMask()
Return a mask holding all technical layers and the external CU layer on back side.
Definition lset.cpp:725
T Min() const
Definition minoptmax.h:29
Definition pad.h:61
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:70
@ COURTYARD_CLEARANCE_CONSTRAINT
Definition drc_rule.h:57
#define COURTYARD_CONFLICT
temporary set when moving footprints having courtyard overlapping
@ F_CrtYd
Definition layer_ids.h:112
@ B_CrtYd
Definition layer_ids.h:111
@ APPEARANCE
Visibility flag has changed.
Definition view_item.h:49
@ TARGET_OVERLAY
Items that may change while the view stays the same (noncached)
Definition definitions.h:35
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition kicad_algo.h:96
int clearance
int actual
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683