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 SHAPE_POLY_SET zoneOutline = zone->GetBoardOutline();
181
182 for( FOOTPRINT* fp : m_FpInMove )
183 {
184 if( disallowFront )
185 {
186 const SHAPE_POLY_SET& frontCourtyard = fp->GetCourtyard( F_CrtYd );
187
188 if( !frontCourtyard.IsEmpty() )
189 {
190 if( zoneOutline.Collide( &frontCourtyard.Outline( 0 ) ) )
191 {
192 m_itemsInConflict.insert( fp );
193 m_itemsInConflict.insert( zone );
194 break;
195 }
196 }
197 }
198
199 if( disallowBack )
200 {
201 const SHAPE_POLY_SET& backCourtyard = fp->GetCourtyard( B_CrtYd );
202
203 if( !backCourtyard.IsEmpty() )
204 {
205 if( zoneOutline.Collide( &backCourtyard.Outline( 0 ) ) )
206 {
207 m_itemsInConflict.insert( fp );
208 m_itemsInConflict.insert( zone );
209 break;
210 }
211 }
212 }
213 }
214 }
215}
216
217
219{
220 m_board = aBoard;
221
222 // Update courtyard data and clear the COURTYARD_CONFLICT flag
223 for( FOOTPRINT* fp: m_board->Footprints() )
224 {
225 fp->ClearFlags( COURTYARD_CONFLICT );
226 fp->BuildCourtyardCaches();
227 }
228}
229
230
232{
233 m_itemsInConflict.clear();
235
236 DRC_CONSTRAINT constraint;
237
238 if( m_drcEngine->QueryWorstConstraint( COURTYARD_CLEARANCE_CONSTRAINT, constraint ) )
240
242
243 return true;
244}
245
246
248 bool aHighlightMoved )
249{
250 // Ensure the "old" conflicts are cleared
252 {
253 item->ClearFlags(COURTYARD_CONFLICT );
254 aView->Update( item, KIGFX::APPEARANCE );
256 }
257
258 m_lastItemsInConflict.clear();
259
260 for( BOARD_ITEM* item: m_itemsInConflict )
261 {
262 if( aHighlightMoved || !alg::contains( m_FpInMove, item ) )
263 {
264 if( !item->HasFlag( COURTYARD_CONFLICT ) )
265 {
266 item->SetFlags( COURTYARD_CONFLICT );
267 aView->Update( item, KIGFX::APPEARANCE );
269 }
270
271 m_lastItemsInConflict.push_back( item );
272 }
273 }
274}
275
276
278{
280 {
281 item->ClearFlags( COURTYARD_CONFLICT );
282 aView->Update( item );
284 }
285}
286
287
BOX2< VECTOR2I > BOX2I
Definition box2.h:918
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:81
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:372
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:554
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:654
constexpr bool Intersects(const BOX2< Vec > &aRect) const
Definition box2.h:307
const MINOPTMAX< int > & GetValue() const
Definition drc_rule.h:196
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:375
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:1835
void MarkTargetDirty(int aTarget)
Set or clear target 'dirty' flag.
Definition view.h:657
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