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#include <view/view.h>
33
35{
36 std::vector<BOX2I> fpBBBoxes( m_FpInMove.size() );
37 BOX2I movingBBox;
38
39 for( size_t i = 0; i < m_FpInMove.size(); i++ )
40 {
41 FOOTPRINT* fpB = m_FpInMove[i];
42
43 BOX2I bbox = fpB->GetBoundingBox( true );
44 movingBBox.Merge( bbox );
45 fpBBBoxes[i] = bbox;
46 }
47
49
50 for( FOOTPRINT* fpA: m_board->Footprints() )
51 {
52 if( fpA->IsSelected() )
53 continue;
54
55 BOX2I fpABBox = fpA->GetBoundingBox( true );
56
57 if( !movingBBox.Intersects( fpABBox ) )
58 continue;
59
60 const SHAPE_POLY_SET& frontA = fpA->GetCourtyard( F_CrtYd );
61 const SHAPE_POLY_SET& backA = fpA->GetCourtyard( B_CrtYd );
62
63 if( frontA.OutlineCount() == 0 && backA.OutlineCount() == 0 )
64 // No courtyards defined and no hole testing against other footprint's courtyards
65 continue;
66
67 BOX2I frontABBox = frontA.BBoxFromCaches();
68 BOX2I backABBox = backA.BBoxFromCaches();
69
72
73 for( size_t inMoveId = 0; inMoveId < m_FpInMove.size(); inMoveId++ )
74 {
75 FOOTPRINT* fpB = m_FpInMove[inMoveId];
76 const SHAPE_POLY_SET& frontB = fpB->GetCourtyard( F_CrtYd );
77 const SHAPE_POLY_SET& backB = fpB->GetCourtyard( B_CrtYd );
78
79 const BOX2I fpBBBox = fpBBBoxes[inMoveId];
80 const BOX2I frontBBBox = frontB.BBoxFromCaches();
81 const BOX2I backBBBox = backB.BBoxFromCaches();
82
83 int clearance;
84 int actual;
85 VECTOR2I pos;
86
87 if( frontA.OutlineCount() > 0 && frontB.OutlineCount() > 0
88 && frontABBox.Intersects( frontBBBox ) )
89 {
90 // Currently, do not use DRC engine for calculation time reasons
91 // DRC_CONSTRAINT constraint = m_drcEngine->EvalRules( COURTYARD_CLEARANCE_CONSTRAINT, fpA, fpB, B_Cu );
92 // constraint.GetValue().Min();
93 clearance = 0;
94
95 if( frontA.Collide( &frontB, clearance, &actual, &pos ) )
96 {
97 m_itemsInConflict.insert( fpA );
98 m_itemsInConflict.insert( fpB );
99 }
100 }
101
102 if( backA.OutlineCount() > 0 && backB.OutlineCount() > 0
103 && backABBox.Intersects( backBBBox ) )
104 {
105 // Currently, do not use DRC engine for calculation time reasons
106 // DRC_CONSTRAINT constraint = m_drcEngine->EvalRules( COURTYARD_CLEARANCE_CONSTRAINT, fpA, fpB, B_Cu );
107 // constraint.GetValue().Min();
108 clearance = 0;
109
110 if( backA.Collide( &backB, clearance, &actual, &pos ) )
111 {
112 m_itemsInConflict.insert( fpA );
113 m_itemsInConflict.insert( fpB );
114 }
115 }
116
117 // Now test if a pad hole of some other footprint is inside the courtyard area
118 // of the moved footprint
119 auto testPadAgainstCourtyards =
120 [&]( const PAD* pad, FOOTPRINT* footprint ) -> bool
121 {
122 if( pad->HasHole() )
123 {
124 std::shared_ptr<SHAPE_SEGMENT> hole = pad->GetEffectiveHoleShape();
125 const SHAPE_POLY_SET& front = footprint->GetCachedCourtyard( F_CrtYd );
126 const SHAPE_POLY_SET& back = footprint->GetCachedCourtyard( B_CrtYd );
127
128 if( front.OutlineCount() > 0 && front.Collide( hole.get(), 0 ) )
129 return true;
130 else if( back.OutlineCount() > 0 && back.Collide( hole.get(), 0 ) )
131 return true;
132 }
133
134 return false;
135 };
136
137 bool skipNextCmp = false;
138
139 if( ( frontA.OutlineCount() > 0 && frontABBox.Intersects( fpBBBox ) )
140 || ( backA.OutlineCount() > 0 && backABBox.Intersects( fpBBBox ) ) )
141 {
142 for( const PAD* padB : fpB->Pads() )
143 {
144 if( testPadAgainstCourtyards( padB, fpA ) )
145 {
146 m_itemsInConflict.insert( fpA );
147 m_itemsInConflict.insert( fpB );
148 skipNextCmp = true;
149 break;
150 }
151 }
152 }
153
154 if( skipNextCmp )
155 continue; // fpA and fpB are already in list
156
157 if( ( frontB.OutlineCount() > 0 && frontBBBox.Intersects( fpABBox ) )
158 || ( backB.OutlineCount() > 0 && backBBBox.Intersects( fpABBox ) ) )
159 {
160 for( const PAD* padA : fpA->Pads() )
161 {
162 if( testPadAgainstCourtyards( padA, fpB ) )
163 {
164 m_itemsInConflict.insert( fpA );
165 m_itemsInConflict.insert( fpB );
166 break;
167 }
168 }
169 }
170 }
171 }
172
173 for( ZONE* zone : m_board->Zones() )
174 {
175 if( !zone->GetIsRuleArea() || !zone->HasKeepoutParametersSet()
176 || !zone->GetDoNotAllowFootprints() )
177 {
178 continue;
179 }
180
181 bool disallowFront = ( zone->GetLayerSet() & LSET::FrontMask() ).any();
182 bool disallowBack = ( zone->GetLayerSet() & LSET::BackMask() ).any();
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( zone->Outline()->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( zone->Outline()->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 );
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 );
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:922
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:322
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:187
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:306
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:67
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:1700
void MarkTargetDirty(int aTarget)
Set or clear target 'dirty' flag.
Definition view.h:640
static const LSET & FrontMask()
Return a mask holding all technical layers and the external CU layer on front side.
Definition lset.cpp:722
static const LSET & BackMask()
Return a mask holding all technical layers and the external CU layer on back side.
Definition lset.cpp:729
T Min() const
Definition minoptmax.h:33
Definition pad.h:55
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
int clearance
int actual
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695