KiCad PCB EDA Suite
Loading...
Searching...
No Matches
creepage_overlay.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
26#include <algorithm>
27#include <chrono>
28
29#include <advanced_config.h>
30#include <base_units.h>
31#include <eda_units.h>
32#include <board.h>
35#include <footprint.h>
36#include <netinfo.h>
37#include <pad.h>
38#include <pcb_track.h>
39#include <pcb_shape.h>
40
41#include <drc/drc_engine.h>
42#include <drc/drc_rule.h>
43
44#include <view/view.h>
45#include <view/view_overlay.h>
46
47
48CREEPAGE_OVERLAY::CREEPAGE_OVERLAY( BOARD* aBoard, std::shared_ptr<DRC_ENGINE> aDrcEngine,
49 KIGFX::VIEW* aView ) :
50 m_board( aBoard ),
51 m_drcEngine( std::move( aDrcEngine ) ),
52 m_view( aView ),
54 m_enabled( false ),
55 m_active( false ),
56 m_skipFrames( 0 )
57{
59 && m_drcEngine->HasRulesForConstraintType( CREEPAGE_CONSTRAINT );
60
61 if( ADVANCED_CFG::GetCfg().m_EnableCreepageSlot && m_board )
62 m_minGrooveWidth = m_board->GetDesignSettings().m_MinGrooveWidth;
63}
64
65
70
71
73{
74 if( m_overlay )
75 {
76 m_overlay->Clear();
77 m_view->Update( m_overlay.get() );
78 }
79}
80
81
82void CREEPAGE_OVERLAY::Start( const std::vector<BOARD_ITEM*>& aMovingItems )
83{
84 if( !m_enabled || aMovingItems.empty() )
85 return;
86
87 std::map<PCB_LAYER_ID, std::set<int>> netsByLayer;
88 std::set<const BOARD_ITEM*> movingItems;
89 LSET copper = LSET::AllCuMask( m_board->GetCopperLayerCount() );
90
91 auto addConnected = [&]( BOARD_CONNECTED_ITEM* aItem )
92 {
93 if( !aItem || aItem->GetNetCode() <= 0 )
94 return;
95
96 for( PCB_LAYER_ID layer : copper.Seq() )
97 {
98 if( aItem->IsOnLayer( layer ) )
99 netsByLayer[layer].insert( aItem->GetNetCode() );
100 }
101 };
102
103 for( BOARD_ITEM* item : aMovingItems )
104 {
105 if( !item )
106 continue;
107
108 movingItems.insert( item );
109
110 if( item->IsConnected() )
111 addConnected( static_cast<BOARD_CONNECTED_ITEM*>( item ) );
112
113 if( item->Type() == PCB_FOOTPRINT_T )
114 {
115 for( PAD* pad : static_cast<FOOTPRINT*>( item )->Pads() )
116 addConnected( pad );
117 }
118 }
119
120 if( netsByLayer.empty() )
121 return;
122
123 BOARD* board = m_board;
124 std::shared_ptr<DRC_ENGINE> drcEngine = m_drcEngine;
125
126 for( const auto& [layer, affectedNets] : netsByLayer )
127 {
128 // Capturing by value keeps the lambda valid for the whole drag
129 auto constraintFn = [board, drcEngine, layer]( int aNetA, int aNetB ) -> double
130 {
131 PCB_TRACK a( board );
132 PCB_TRACK b( board );
133 a.SetNetCode( aNetA );
134 b.SetNetCode( aNetB );
135 a.SetLayer( layer );
136 b.SetLayer( layer );
137
138 DRC_CONSTRAINT c = drcEngine->EvalRules( CREEPAGE_CONSTRAINT, &a, &b, layer );
139 return c.Value().Min();
140 };
141
142 // The largest constraint for any affected pair sets the search radius and near band
143 double maxConstraint = 0.0;
144
145 for( int affected : affectedNets )
146 {
147 for( const auto& [netCode, net] : m_board->GetNetInfo().NetsByNetcode() )
148 {
149 if( netCode <= 0 || netCode == affected )
150 continue;
151
152 maxConstraint = std::max( maxConstraint, constraintFn( affected, netCode ) );
153 }
154 }
155
156 if( maxConstraint <= 0 )
157 continue;
158
159 int nearMargin = static_cast<int>( maxConstraint / 2 );
160 int margin = static_cast<int>( maxConstraint ) + nearMargin;
161
162 auto engine = std::make_unique<CREEPAGE_ENGINE>( *m_board );
163 engine->SetMinGrooveWidth( m_minGrooveWidth );
164 engine->BeginInteractive( layer, affectedNets, movingItems, margin, constraintFn );
165 m_engines[layer] = { std::move( engine ), nearMargin };
166 }
167
168 if( m_engines.empty() )
169 return;
170
171 if( !m_overlay )
172 {
173 m_overlay = m_view->MakeOverlay();
174 }
175
176 m_active = true;
177}
178
179
181{
182 if( !m_active || !m_overlay )
183 return;
184
185 if( m_skipFrames > 0 )
186 {
187 --m_skipFrames;
188 return;
189 }
190
191 auto t0 = std::chrono::steady_clock::now();
192 std::vector<CREEPAGE_RESULT> results;
193
194 for( auto& [layer, le] : m_engines )
195 {
196 std::vector<CREEPAGE_RESULT> layerResults = le.m_engine->Update( le.m_nearMargin );
197 results.insert( results.end(), layerResults.begin(), layerResults.end() );
198 }
199
200 double elapsedMs = std::chrono::duration<double, std::milli>(
201 std::chrono::steady_clock::now() - t0 )
202 .count();
203
204 // Budget one 60 Hz frame; a heavier Update amortizes by skipping proportional motion frames
205 constexpr double frameBudgetMs = 16.0;
206 m_skipFrames = static_cast<int>( elapsedMs / frameBudgetMs );
207
208 m_overlay->Clear();
209
210 const COLOR4D violationColor( 0.92, 0.18, 0.18, 1.0 );
211 const COLOR4D nearColor( 0.95, 0.62, 0.10, 0.85 );
212 const double lineWidth = pcbIUScale.mmToIU( 0.12 );
213
214 for( const CREEPAGE_RESULT& r : results )
215 {
216 m_overlay->SetStrokeColor( r.m_violation ? violationColor : nearColor );
217 m_overlay->SetLineWidth( lineWidth );
218
219 for( const PCB_SHAPE& shape : r.m_path )
220 {
221 if( shape.GetShape() == SHAPE_T::ARC )
222 {
223 EDA_ANGLE start( shape.GetStart() - shape.GetCenter() );
224 m_overlay->Arc( shape.GetCenter(), shape.GetRadius(), start,
225 start + shape.GetArcAngle() );
226 }
227 else
228 {
229 m_overlay->Segment( shape.GetStart(), shape.GetEnd(), lineWidth );
230 }
231 }
232
233 m_overlay->SetGlyphSize( VECTOR2I( pcbIUScale.mmToIU( 0.6 ), pcbIUScale.mmToIU( 0.6 ) ) );
235 r.m_distance ),
236 r.m_start, ANGLE_0 );
237 }
238
239 m_view->Update( m_overlay.get() );
240}
241
242
244{
245 for( auto& [layer, le] : m_engines )
246 {
247 if( le.m_engine )
248 le.m_engine->EndInteractive();
249 }
250
251 m_engines.clear();
252 m_active = false;
253
254 if( m_overlay )
255 {
256 clearOverlay();
257 m_view->Remove( m_overlay.get() );
258 m_overlay.reset();
259 }
260}
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
virtual bool SetNetCode(int aNetCode, bool aNoAssert)
Set net using a net code.
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
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
std::shared_ptr< DRC_ENGINE > m_drcEngine
std::shared_ptr< KIGFX::VIEW_OVERLAY > m_overlay
std::map< PCB_LAYER_ID, LAYER_ENGINE > m_engines
KIGFX::VIEW * m_view
CREEPAGE_OVERLAY(BOARD *aBoard, std::shared_ptr< DRC_ENGINE > aDrcEngine, KIGFX::VIEW *aView)
void Update()
Recompute and redraw at the items' current board positions.
void Start(const std::vector< BOARD_ITEM * > &aMovingItems)
Begin a drag session for the given items, on every copper layer they occupy.
void Stop()
End the session and clear the overlay.
MINOPTMAX< int > & Value()
Definition drc_rule.h:197
EDA_ANGLE GetArcAngle() const
int GetRadius() const
SHAPE_T GetShape() const
Definition eda_shape.h:185
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition eda_shape.h:240
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition eda_shape.h:190
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:101
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:63
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
static const LSET & AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition lset.cpp:604
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition lset.cpp:309
T Min() const
Definition minoptmax.h:29
Definition pad.h:61
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition pcb_shape.h:78
@ CREEPAGE_CONSTRAINT
Definition drc_rule.h:52
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:411
bool m_RealtimeCreepage
Use the realtime (V2) creepage engine.
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
KICOMMON_API wxString MessageTextFromValue(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, double aValue, bool aAddUnitsText=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
A helper to convert the double length aValue to a string in inches, millimeters, or unscaled units.
STL namespace.
Result of a single creepage query between two nets on one layer.
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition typeinfo.h:79
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683