KiCad PCB EDA Suite
Loading...
Searching...
No Matches
drc_test_provider_edge_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
24#include <common.h>
25#include <pcb_shape.h>
26#include <pcb_board_outline.h>
28#include <footprint.h>
29#include <pcb_track.h>
30#include <geometry/seg.h>
32#include <drc/drc_engine.h>
33#include <drc/drc_item.h>
34#include <drc/drc_rule.h>
36#include "drc_rtree.h"
37
38/*
39 Board edge clearance test. Checks all items for their mechanical clearances against the board
40 edge.
41 Errors generated:
42 - DRCE_EDGE_CLEARANCE
43 - DRCE_SILK_EDGE_CLEARANCE
44*/
45
52
53
55{
56public:
61
63
64 virtual bool Run() override;
65
66 virtual const wxString GetName() const override { return wxT( "edge_clearance" ); }
67
68private:
69 void resolveSilkDisposition( BOARD_ITEM* aItem, const SHAPE* aItemShape, const SHAPE_POLY_SET& aBoardOutline );
70
71 bool testAgainstEdge( BOARD_ITEM* item, SHAPE* itemShape, BOARD_ITEM* other, DRC_CONSTRAINT_T aConstraintType,
72 PCB_DRC_CODE aErrorCode );
73
74private:
75 std::vector<PAD*> m_castellatedPads;
79
80 std::map<BOARD_ITEM*, SILK_DISPOSITION> m_silkDisposition;
81};
82
83
85 const SHAPE_POLY_SET& aBoardOutline )
86{
87 SILK_DISPOSITION disposition = UNKNOWN;
88
89 if( aItemShape->Type() == SH_COMPOUND )
90 {
91 const SHAPE_COMPOUND* compound = static_cast<const SHAPE_COMPOUND*>( aItemShape );
92
93 for( const SHAPE* elem : compound->Shapes() )
94 {
95 SILK_DISPOSITION elem_disposition = aBoardOutline.Contains( elem->Centre() ) ? ON_BOARD : OFF_BOARD;
96
97 if( disposition == UNKNOWN )
98 {
99 disposition = elem_disposition;
100 }
101 else if( disposition != elem_disposition )
102 {
103 disposition = CROSSES_EDGE;
104 break;
105 }
106 }
107 }
108 else
109 {
110 disposition = aBoardOutline.Contains( aItemShape->Centre() ) ? ON_BOARD : OFF_BOARD;
111 }
112
113 m_silkDisposition[aItem] = disposition;
114
115 if( disposition == CROSSES_EDGE )
116 {
117 BOARD_ITEM* nearestEdge = nullptr;
118 VECTOR2I itemPos = aItem->GetCenter();
119 VECTOR2I nearestEdgePt = aBoardOutline.Outline( 0 ).NearestPoint( itemPos, false );
120
121 for( int outlineIdx = 1; outlineIdx < aBoardOutline.OutlineCount(); ++outlineIdx )
122 {
123 VECTOR2I otherEdgePt = aBoardOutline.Outline( outlineIdx ).NearestPoint( itemPos, false );
124
125 if( otherEdgePt.SquaredDistance( itemPos ) < nearestEdgePt.SquaredDistance( itemPos ) )
126 nearestEdgePt = otherEdgePt;
127 }
128
129 for( BOARD_ITEM* edge : m_edgesTree.GetObjectsAt( nearestEdgePt, Edge_Cuts, m_epsilon ) )
130 {
131 if( edge->HitTest( nearestEdgePt, m_epsilon ) )
132 {
133 nearestEdge = edge;
134 break;
135 }
136 }
137
138 if( !nearestEdge )
139 return;
140
141 auto constraint = m_drcEngine->EvalRules( SILK_CLEARANCE_CONSTRAINT, nearestEdge, aItem, UNDEFINED_LAYER );
142 int minClearance = constraint.GetValue().Min();
143
144 if( constraint.GetSeverity() != RPT_SEVERITY_IGNORE && minClearance >= 0 )
145 {
146 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_SILK_EDGE_CLEARANCE );
147
148 // Report clearance info if there is any, even though crossing is just a straight-up collision
149 if( minClearance > 0 )
150 {
151 drcItem->SetErrorDetail( formatMsg( _( "(%s clearance %s; actual %s)" ),
152 constraint.GetName(),
153 minClearance,
154 0 ) );
155 }
156
157 drcItem->SetItems( nearestEdge->m_Uuid, aItem->m_Uuid );
158 drcItem->SetViolatingRule( constraint.GetParentRule() );
159 reportTwoPointGeometry( drcItem, nearestEdgePt, nearestEdgePt, nearestEdgePt, aItem->GetLayer() );
160 }
161 }
162#if 0
163 // If you want "Silk outside board edge" errors:
164 else if( disposition == OFF_BOARD )
165 {
166 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_SILK_EDGE_CLEARANCE );
167 drcItem->SetErrorMessage( _( "Silkscreen outside board edge" ) );
168
169 drcItem->SetItems( aItem->m_Uuid );
170 reportTwoPointGeometry( drcItem, aItem->GetCenter(), aItem->GetCenter(), aItem->GetCenter(),
171 aItem->GetLayer() );
172 }
173#endif
174}
175
176
178 DRC_CONSTRAINT_T aConstraintType, PCB_DRC_CODE aErrorCode )
179{
180 std::shared_ptr<SHAPE> shape;
181
182 if( edge->Type() == PCB_PAD_T )
183 shape = edge->GetEffectiveHoleShape();
184 else
185 shape = edge->GetEffectiveShape( Edge_Cuts );
186
187 auto constraint = m_drcEngine->EvalRules( aConstraintType, edge, item, UNDEFINED_LAYER );
188 int minClearance = constraint.GetValue().Min();
189 int actual;
190 VECTOR2I pos;
191
192 if( constraint.GetSeverity() != RPT_SEVERITY_IGNORE && minClearance >= 0 )
193 {
194 if( itemShape->Collide( shape.get(), minClearance, &actual, &pos ) )
195 {
196 // Exact clearance is allowed
197 if( minClearance > 0 && actual == minClearance )
198 return true;
199
200 if( item->Type() == PCB_TRACE_T || item->Type() == PCB_ARC_T )
201 {
202 // Edge collisions are allowed inside the holes of castellated pads
203 for( PAD* castellatedPad : m_castellatedPads )
204 {
205 if( castellatedPad->GetEffectiveHoleShape()->Collide( pos ) )
206 return true;
207 }
208 }
209
210 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( aErrorCode );
211
212 // Only report clearance info if there is any; otherwise it's just a straight collision
213 if( minClearance > 0 )
214 {
215 drcItem->SetErrorDetail( formatMsg( _( "(%s clearance %s; actual %s)" ),
216 constraint.GetName(),
217 minClearance,
218 actual ) );
219 }
220
221 drcItem->SetItems( edge->m_Uuid, item->m_Uuid );
222 drcItem->SetViolatingRule( constraint.GetParentRule() );
223 reportTwoItemGeometry( drcItem, pos, edge, item, Edge_Cuts, actual );
224
225 if( aErrorCode == DRCE_SILK_EDGE_CLEARANCE )
227
228 if( item->Type() == PCB_TRACE_T || item->Type() == PCB_ARC_T )
229 return m_drcEngine->GetReportAllTrackErrors();
230 else
231 return false; // don't report violations with multiple edges; one is enough
232 }
233 }
234
235 return true;
236}
237
238
240{
241 if( !m_drcEngine->IsErrorLimitExceeded( DRCE_EDGE_CLEARANCE ) )
242 {
243 if( !reportPhase( _( "Checking copper to board edge clearances..." ) ) )
244 return false; // DRC cancelled
245 }
246 else if( !m_drcEngine->IsErrorLimitExceeded( DRCE_SILK_EDGE_CLEARANCE ) )
247 {
248 if( !reportPhase( _( "Checking silk to board edge clearances..." ) ) )
249 return false; // DRC cancelled
250 }
251 else
252 {
253 REPORT_AUX( wxT( "Edge clearance violations ignored. Tests not run." ) );
254 return true; // continue with other tests
255 }
256
257 m_board = m_drcEngine->GetBoard();
258 m_castellatedPads.clear();
259 m_epsilon = m_board->GetDesignSettings().GetDRCEpsilon();
260 m_edgesTree.clear();
261 m_silkDisposition.clear();
262
263 DRC_CONSTRAINT worstClearanceConstraint;
264
265 if( m_drcEngine->QueryWorstConstraint( EDGE_CLEARANCE_CONSTRAINT, worstClearanceConstraint ) )
266 m_largestEdgeClearance = worstClearanceConstraint.GetValue().Min();
267
268 /*
269 * Build an RTree of the various edges (including NPTH holes) and margins found on the board.
270 */
271 std::vector<std::unique_ptr<PCB_SHAPE>> edges;
272
274 [&]( BOARD_ITEM *item ) -> bool
275 {
276 PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( item );
277 STROKE_PARAMS stroke = shape->GetStroke();
278
279 if( item->IsOnLayer( Edge_Cuts ) )
280 stroke.SetWidth( 0 );
281
282 if( shape->GetShape() == SHAPE_T::RECTANGLE && !shape->IsSolidFill() )
283 {
284 // A single rectangle for the board would defeat the RTree, so convert to edges
285 if( shape->GetCornerRadius() > 0 )
286 {
287 for( SHAPE* seg : shape->MakeEffectiveShapes( true ) )
288 {
289 wxCHECK2( dynamic_cast<SHAPE_SEGMENT*>( seg ), continue );
290
291 edges.emplace_back( static_cast<PCB_SHAPE*>( shape->Clone() ) );
292 edges.back()->SetShape( SHAPE_T::SEGMENT );
293 edges.back()->SetStart( seg->GetStart() );
294 edges.back()->SetEnd( seg->GetEnd() );
295 edges.back()->SetStroke( stroke );
296 }
297 }
298 else
299 {
300 edges.emplace_back( static_cast<PCB_SHAPE*>( shape->Clone() ) );
301 edges.back()->SetShape( SHAPE_T::SEGMENT );
302 edges.back()->SetEndX( shape->GetStartX() );
303 edges.back()->SetStroke( stroke );
304 edges.emplace_back( static_cast<PCB_SHAPE*>( shape->Clone() ) );
305 edges.back()->SetShape( SHAPE_T::SEGMENT );
306 edges.back()->SetEndY( shape->GetStartY() );
307 edges.back()->SetStroke( stroke );
308 edges.emplace_back( static_cast<PCB_SHAPE*>( shape->Clone() ) );
309 edges.back()->SetShape( SHAPE_T::SEGMENT );
310 edges.back()->SetStartX( shape->GetEndX() );
311 edges.back()->SetStroke( stroke );
312 edges.emplace_back( static_cast<PCB_SHAPE*>( shape->Clone() ) );
313 edges.back()->SetShape( SHAPE_T::SEGMENT );
314 edges.back()->SetStartY( shape->GetEndY() );
315 edges.back()->SetStroke( stroke );
316 }
317 }
318 else if( shape->GetShape() == SHAPE_T::POLY && !shape->IsSolidFill() )
319 {
320 // A single polygon for the board would defeat the RTree, so convert to edges.
321 SHAPE_LINE_CHAIN poly = shape->GetPolyShape().Outline( 0 );
322
323 for( size_t ii = 0; ii < poly.GetSegmentCount(); ++ii )
324 {
325 SEG seg = poly.CSegment( ii );
326 edges.emplace_back( static_cast<PCB_SHAPE*>( shape->Clone() ) );
327 edges.back()->SetShape( SHAPE_T::SEGMENT );
328 edges.back()->SetStart( seg.A );
329 edges.back()->SetEnd( seg.B );
330 edges.back()->SetStroke( stroke );
331 }
332 }
333 else
334 {
335 edges.emplace_back( static_cast<PCB_SHAPE*>( shape->Clone() ) );
336 edges.back()->SetStroke( stroke );
337 }
338
339 return true;
340 } );
341
342 for( const std::unique_ptr<PCB_SHAPE>& edge : edges )
343 {
344 for( PCB_LAYER_ID layer : { Edge_Cuts, Margin } )
345 {
346 if( edge->IsOnLayer( layer ) )
347 m_edgesTree.Insert( edge.get(), layer, m_largestEdgeClearance );
348 }
349 }
350
351 for( FOOTPRINT* footprint : m_board->Footprints() )
352 {
353 for( PAD* pad : footprint->Pads() )
354 {
355 if( pad->GetAttribute() == PAD_ATTRIB::NPTH && pad->HasHole() )
356 {
357 // edge-clearances are for milling tolerances (drilling tolerances are handled
358 // by hole-clearances)
359 if( pad->GetDrillSizeX() != pad->GetDrillSizeY() )
361 }
362
363 if( pad->GetProperty() == PAD_PROP::CASTELLATED )
364 m_castellatedPads.push_back( pad );
365 }
366 }
367
368 /*
369 * Test copper and silk items against the set of edges.
370 */
371 const int progressDelta = 200;
372 int count = 0;
373 int ii = 0;
374
376 [&]( BOARD_ITEM *item ) -> bool
377 {
378 count++;
379 return true;
380 } );
381
383 [&]( BOARD_ITEM *item ) -> bool
384 {
385 bool testCopper = !m_drcEngine->IsErrorLimitExceeded( DRCE_EDGE_CLEARANCE );
386 bool testSilk = !m_drcEngine->IsErrorLimitExceeded( DRCE_SILK_EDGE_CLEARANCE );
387
388 if( !testCopper && !testSilk )
389 return false; // All limits exceeded; we're done
390
391 if( !reportProgress( ii++, count, progressDelta ) )
392 return false; // DRC cancelled; we're done
393
394 if( isInvisibleText( item ) )
395 return true; // Continue with other items
396
397 if( item->Type() == PCB_PAD_T )
398 {
399 PAD* pad = static_cast<PAD*>( item );
400
401 if( pad->GetProperty() == PAD_PROP::CASTELLATED || pad->GetAttribute() == PAD_ATTRIB::CONN )
402 return true; // Continue with other items
403 }
404
405 std::vector<PCB_LAYER_ID> layersToTest;
406
407 switch( item->Type() )
408 {
409 case PCB_PAD_T:
410 layersToTest = static_cast<PAD*>( item )->Padstack().UniqueLayers();
411 break;
412
413 case PCB_VIA_T:
414 layersToTest = static_cast<PCB_VIA*>( item )->Padstack().UniqueLayers();
415 break;
416
417 default:
418 layersToTest = { UNDEFINED_LAYER };
419 }
420
421 for( PCB_LAYER_ID shapeLayer : layersToTest )
422 {
423 const std::shared_ptr<SHAPE>& itemShape = item->GetEffectiveShape( shapeLayer );
424
425 for( PCB_LAYER_ID testLayer : { Edge_Cuts, Margin } )
426 {
427 if( testCopper && item->IsOnCopperLayer() )
428 {
429 m_edgesTree.QueryColliding( item, shapeLayer, testLayer, nullptr,
430 [&]( BOARD_ITEM* edge ) -> bool
431 {
432 return testAgainstEdge( item, itemShape.get(), edge,
435 },
437 }
438
439 if( testSilk && ( item->IsOnLayer( F_SilkS ) || item->IsOnLayer( B_SilkS ) ) )
440 {
441 m_edgesTree.QueryColliding( item, shapeLayer, testLayer, nullptr,
442 [&]( BOARD_ITEM* edge ) -> bool
443 {
444 return testAgainstEdge( item, itemShape.get(), edge,
447 },
449 }
450 }
451
452 if( testSilk && ( item->IsOnLayer( F_SilkS ) || item->IsOnLayer( B_SilkS ) ) )
453 {
454 if( m_silkDisposition[item] == UNKNOWN && m_board->BoardOutline()->HasOutline() )
455 resolveSilkDisposition( item, itemShape.get(), m_board->BoardOutline()->GetOutline() );
456 }
457 }
458
459 return true;
460 } );
461
462 return !m_drcEngine->IsCancelled();
463}
464
465
466namespace detail
467{
469}
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:83
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition board_item.h:236
virtual VECTOR2I GetCenter() const
This defaults to the center of the bounding box if not overridden.
Definition board_item.h:116
virtual bool IsOnLayer(PCB_LAYER_ID aLayer) const
Test to see if this object is on the given layer.
Definition board_item.h:318
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT) const
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
virtual bool IsOnCopperLayer() const
Definition board_item.h:155
virtual std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const
const MINOPTMAX< int > & GetValue() const
Definition drc_rule.h:186
static std::shared_ptr< DRC_ITEM > Create(int aErrorCode)
Constructs a DRC_ITEM for the given error code.
Definition drc_item.cpp:400
Implement an R-tree for fast spatial and layer indexing of connectable items.
Definition drc_rtree.h:50
void resolveSilkDisposition(BOARD_ITEM *aItem, const SHAPE *aItemShape, const SHAPE_POLY_SET &aBoardOutline)
virtual bool Run() override
Run this provider against the given PCB with configured options (if any).
virtual ~DRC_TEST_PROVIDER_EDGE_CLEARANCE()=default
std::map< BOARD_ITEM *, SILK_DISPOSITION > m_silkDisposition
virtual const wxString GetName() const override
bool testAgainstEdge(BOARD_ITEM *item, SHAPE *itemShape, BOARD_ITEM *other, DRC_CONSTRAINT_T aConstraintType, PCB_DRC_CODE aErrorCode)
static std::vector< KICAD_T > s_allBasicItemsButZones
virtual bool reportPhase(const wxString &aStageName)
int forEachGeometryItem(const std::vector< KICAD_T > &aTypes, const LSET &aLayers, const std::function< bool(BOARD_ITEM *)> &aFunc)
void reportTwoItemGeometry(std::shared_ptr< DRC_ITEM > &aDrcItem, const VECTOR2I &aMarkerPos, const BOARD_ITEM *aItem1, const BOARD_ITEM *aItem2, PCB_LAYER_ID aLayer, int aDistance)
void reportTwoPointGeometry(std::shared_ptr< DRC_ITEM > &aDrcItem, const VECTOR2I &aMarkerPos, const VECTOR2I &ptA, const VECTOR2I &ptB, PCB_LAYER_ID aLayer)
bool isInvisibleText(const BOARD_ITEM *aItem) const
wxString formatMsg(const wxString &aFormatString, const wxString &aSource, double aConstraint, double aActual, EDA_DATA_TYPE aDataType=EDA_DATA_TYPE::DISTANCE)
virtual bool reportProgress(size_t aCount, size_t aSize, size_t aDelta=1)
const KIID m_Uuid
Definition eda_item.h:516
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
int GetStartY() const
Definition eda_shape.h:174
int GetEndX() const
Definition eda_shape.h:217
virtual std::vector< SHAPE * > MakeEffectiveShapes(bool aEdgeOnly=false) const
Make a set of SHAPE objects representing the EDA_SHAPE.
Definition eda_shape.h:378
SHAPE_POLY_SET & GetPolyShape()
Definition eda_shape.h:336
SHAPE_T GetShape() const
Definition eda_shape.h:168
int GetEndY() const
Definition eda_shape.h:216
bool IsSolidFill() const
Definition eda_shape.h:117
int GetStartX() const
Definition eda_shape.h:175
int GetCornerRadius() const
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
static const LSET & AllLayersMask()
Definition lset.cpp:624
T Min() const
Definition minoptmax.h:33
Definition pad.h:55
STROKE_PARAMS GetStroke() const override
Definition pcb_shape.h:91
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition seg.h:42
VECTOR2I A
Definition seg.h:49
VECTOR2I B
Definition seg.h:50
SHAPE_TYPE Type() const
Return the type of the shape.
Definition shape.h:98
const std::vector< SHAPE * > & Shapes() const
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
const VECTOR2I NearestPoint(const VECTOR2I &aP, bool aAllowInternalShapePoints=true) const
Find a point on the line chain that is closest to point aP.
virtual size_t GetSegmentCount() const override
const SEG CSegment(int aIndex) const
Return a constant copy of the aIndex segment in the line chain.
Represent a set of closed polygons.
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.
bool Contains(const VECTOR2I &aP, int aSubpolyIndex=-1, int aAccuracy=0, bool aUseBBoxCaches=false) const
Return true if a given subpolygon contains the point aP.
An abstract shape on 2D plane.
Definition shape.h:126
virtual bool Collide(const VECTOR2I &aP, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const
Check if the boundary of shape (this) lies closer to the point aP than aClearance,...
Definition shape.h:181
virtual VECTOR2I Centre() const
Compute a center-of-mass of the shape.
Definition shape.h:232
Simple container to manage line stroke parameters.
void SetWidth(int aWidth)
constexpr extended_type SquaredDistance(const VECTOR2< T > &aVector) const
Compute the squared distance between two vectors.
Definition vector2d.h:569
The common library.
PCB_DRC_CODE
Definition drc_item.h:38
@ DRCE_SILK_EDGE_CLEARANCE
Definition drc_item.h:99
@ DRCE_EDGE_CLEARANCE
Definition drc_item.h:47
DRC_CONSTRAINT_T
Definition drc_rule.h:47
@ SILK_CLEARANCE_CONSTRAINT
Definition drc_rule.h:56
@ EDGE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:53
#define REPORT_AUX(s)
#define _(s)
@ SEGMENT
Definition eda_shape.h:45
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
Definition eda_shape.h:46
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
@ Edge_Cuts
Definition layer_ids.h:112
@ Margin
Definition layer_ids.h:113
@ F_SilkS
Definition layer_ids.h:100
@ UNDEFINED_LAYER
Definition layer_ids.h:61
@ B_SilkS
Definition layer_ids.h:101
static DRC_REGISTER_TEST_PROVIDER< DRC_TEST_PROVIDER_ANNULAR_WIDTH > dummy
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition padstack.h:103
@ CONN
Like smd, does not appear on the solder paste layer (default) Note: also has a special attribute in G...
Definition padstack.h:100
@ CASTELLATED
a pad with a castellated through hole
Definition padstack.h:121
@ RPT_SEVERITY_IGNORE
@ SH_COMPOUND
compound shape, consisting of multiple simple shapes
Definition shape.h:53
int actual
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition typeinfo.h:88
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:97
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:87
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition typeinfo.h:98
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition typeinfo.h:96
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695