KiCad PCB EDA Suite
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 for( FOOTPRINT* fpA: m_board->Footprints() )
36 {
37 if( fpA->IsSelected() )
38 continue;
39
40 const SHAPE_POLY_SET& frontA = fpA->GetCourtyard( F_CrtYd );
41 const SHAPE_POLY_SET& backA = fpA->GetCourtyard( B_CrtYd );
42
43 if( frontA.OutlineCount() == 0 && backA.OutlineCount() == 0 )
44 // No courtyards defined and no hole testing against other footprint's courtyards
45 continue;
46
47 BOX2I frontBBox = frontA.BBoxFromCaches();
48 BOX2I backBBox = backA.BBoxFromCaches();
49
52
53 BOX2I fpABBox = fpA->GetBoundingBox();
54
55 for( FOOTPRINT* fpB : m_FpInMove )
56 {
57 BOX2I fpBBBox = fpB->GetBoundingBox();
58 const SHAPE_POLY_SET& frontB = fpB->GetCourtyard( F_CrtYd );
59 const SHAPE_POLY_SET& backB = fpB->GetCourtyard( B_CrtYd );
60 DRC_CONSTRAINT constraint;
61 int clearance;
62 int actual;
63 VECTOR2I pos;
64
65 if( frontA.OutlineCount() > 0 && frontB.OutlineCount() > 0
66 && frontBBox.Intersects( frontB.BBoxFromCaches() ) )
67 {
68 // Currently, do not use DRC engine for calculation time reasons
69 // constraint = m_drcEngine->EvalRules( COURTYARD_CLEARANCE_CONSTRAINT, fpA, fpB, B_Cu );
70 // constraint.GetValue().Min();
71 clearance = 0;
72
73 if( frontA.Collide( &frontB, clearance, &actual, &pos ) )
74 {
75 m_itemsInConflict.insert( fpA );
76 m_itemsInConflict.insert( fpB );
77 }
78 }
79
80 if( backA.OutlineCount() > 0 && backB.OutlineCount() > 0
81 && backBBox.Intersects( backB.BBoxFromCaches() ) )
82 {
83 // Currently, do not use DRC engine for calculation time reasons
84 // constraint = m_drcEngine->EvalRules( COURTYARD_CLEARANCE_CONSTRAINT, fpA, fpB, B_Cu );
85 // constraint.GetValue().Min();
86 clearance = 0;
87
88 if( backA.Collide( &backB, clearance, &actual, &pos ) )
89 {
90 m_itemsInConflict.insert( fpA );
91 m_itemsInConflict.insert( fpB );
92 }
93 }
94
95 // Now test if a pad hole of some other footprint is inside the courtyard area
96 // of the moved footprint
97 auto testPadAgainstCourtyards =
98 [&]( const PAD* pad, FOOTPRINT* footprint ) -> bool
99 {
100 if( pad->HasHole() )
101 {
102 std::shared_ptr<SHAPE_SEGMENT> hole = pad->GetEffectiveHoleShape();
103 const SHAPE_POLY_SET& front = footprint->GetCourtyard( F_CrtYd );
104 const SHAPE_POLY_SET& back = footprint->GetCourtyard( B_CrtYd );
105
106 if( front.OutlineCount() > 0 && front.Collide( hole.get(), 0 ) )
107 return true;
108 else if( back.OutlineCount() > 0 && back.Collide( hole.get(), 0 ) )
109 return true;
110 }
111
112 return false;
113 };
114
115 bool skipNextCmp = false;
116
117 if( ( frontA.OutlineCount() > 0 && frontA.BBoxFromCaches().Intersects( fpBBBox ) )
118 || ( backA.OutlineCount() > 0 && backA.BBoxFromCaches().Intersects( fpBBBox ) ) )
119 {
120 for( const PAD* padB : fpB->Pads() )
121 {
122 if( testPadAgainstCourtyards( padB, fpA ) )
123 {
124 m_itemsInConflict.insert( fpA );
125 m_itemsInConflict.insert( fpB );
126 skipNextCmp = true;
127 break;
128 }
129 }
130 }
131
132 if( skipNextCmp )
133 continue; // fpA and fpB are already in list
134
135 if( ( frontB.OutlineCount() > 0 && frontB.BBoxFromCaches().Intersects( fpABBox ) )
136 || ( backB.OutlineCount() > 0 && backB.BBoxFromCaches().Intersects( fpABBox ) ) )
137 {
138 for( const PAD* padA : fpA->Pads() )
139 {
140 if( testPadAgainstCourtyards( padA, fpB ) )
141 {
142 m_itemsInConflict.insert( fpA );
143 m_itemsInConflict.insert( fpB );
144 break;
145 }
146 }
147 }
148 }
149 }
150
151 for( ZONE* zone : m_board->Zones() )
152 {
153 if( !zone->GetIsRuleArea() || !zone->GetDoNotAllowFootprints() )
154 continue;
155
156 bool disallowFront = ( zone->GetLayerSet() & LSET::FrontMask() ).any();
157 bool disallowBack = ( zone->GetLayerSet() & LSET::BackMask() ).any();
158
159 for( FOOTPRINT* fp : m_FpInMove )
160 {
161 if( disallowFront )
162 {
163 const SHAPE_POLY_SET& frontCourtyard = fp->GetCourtyard( F_CrtYd );
164
165 if( !frontCourtyard.IsEmpty() )
166 {
167 if( zone->Outline()->Collide( &frontCourtyard.Outline( 0 ) ) )
168 {
169 m_itemsInConflict.insert( fp );
170 m_itemsInConflict.insert( zone );
171 break;
172 }
173 }
174 }
175
176 if( disallowBack )
177 {
178 const SHAPE_POLY_SET& backCourtyard = fp->GetCourtyard( B_CrtYd );
179
180 if( !backCourtyard.IsEmpty() )
181 {
182 if( zone->Outline()->Collide( &backCourtyard.Outline( 0 ) ) )
183 {
184 m_itemsInConflict.insert( fp );
185 m_itemsInConflict.insert( zone );
186 break;
187 }
188 }
189 }
190 }
191 }
192}
193
194
196{
197 m_board = aBoard;
198
199 // Update courtyard data and clear the COURTYARD_CONFLICT flag
200 for( FOOTPRINT* fp: m_board->Footprints() )
201 {
203 fp->BuildCourtyardCaches();
204 }
205}
206
207
209{
210 m_itemsInConflict.clear();
212
213 DRC_CONSTRAINT constraint;
214
217
219
220 return true;
221}
222
223
225 bool aHighlightMoved )
226{
227 // Ensure the "old" conflicts are cleared
229 {
230 item->ClearFlags(COURTYARD_CONFLICT );
231 aView->Update( item );
233 }
234
235 m_lastItemsInConflict.clear();
236
237 for( BOARD_ITEM* item: m_itemsInConflict )
238 {
239 if( aHighlightMoved || !alg::contains( m_FpInMove, item ) )
240 {
241 if( !item->HasFlag( COURTYARD_CONFLICT ) )
242 {
243 item->SetFlags( COURTYARD_CONFLICT );
244 aView->Update( item );
246 }
247
248 m_lastItemsInConflict.push_back( item );
249 }
250 }
251}
252
253
255{
257 {
258 item->ClearFlags( COURTYARD_CONFLICT );
259 aView->Update( item );
261 }
262}
263
264
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:70
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:265
ZONES & Zones()
Definition: board.h:313
FOOTPRINTS & Footprints()
Definition: board.h:307
bool Intersects(const BOX2< Vec > &aRect) const
Definition: box2.h:269
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:506
const MINOPTMAX< int > & GetValue() const
Definition: drc_rule.h:141
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:141
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:69
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:1591
void MarkTargetDirty(int aTarget)
Set or clear target 'dirty' flag.
Definition: view.h:617
static LSET FrontMask()
Return a mask holding all technical layers and the external CU layer on front side.
Definition: lset.cpp:895
static LSET BackMask()
Return a mask holding all technical layers and the external CU layer on back side.
Definition: lset.cpp:902
T Min() const
Definition: minoptmax.h:33
Definition: pad.h:59
Represent a set of closed polygons.
bool IsEmpty() const
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)
int OutlineCount() const
Return the number of vertices in a given outline/hole.
const BOX2I BBoxFromCaches() const
Handle a list of polygons defining a copper zone.
Definition: zone.h:57
@ COURTYARD_CLEARANCE_CONSTRAINT
Definition: drc_rule.h:52
#define COURTYARD_CONFLICT
temporary set when moving footprints having courtyard overlapping
@ F_CrtYd
Definition: layer_ids.h:117
@ B_CrtYd
Definition: layer_ids.h:116
@ TARGET_OVERLAY
Items that may change while the view stays the same (noncached)
Definition: definitions.h:50
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition: kicad_algo.h:99