KiCad PCB EDA Suite
Loading...
Searching...
No Matches
api_pcb_utils.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) 2023 Jon Evans <[email protected]>
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21#include <algorithm>
22#include <ranges>
23
24#include <api/api_pcb_utils.h>
25#include <api/api_enums.h>
26#include <api/board/board.pb.h>
27#include <api/api_utils.h>
28#include <board.h>
29#include <embedded_files.h>
32#include <footprint.h>
33#include <lset.h>
34#include <pad.h>
35#include <pcb_group.h>
36#include <pcb_generator.h>
37#include <generators_mgr.h>
39#include <mmh3_hash.h>
40#include <pcb_barcode.h>
41#include <pcb_grid_item.h>
42#include <pcb_reference_image.h>
43#include <pcb_shape.h>
44#include <pcb_3d_body.h>
45#include <pcb_point.h>
46#include <pcb_track.h>
47#include <pcb_field.h>
48#include <pcb_text.h>
49#include <pcb_textbox.h>
50#include <pcb_drill_chart.h>
51#include <pcb_drill_map.h>
52#include <pcb_table.h>
53#include <pcb_dimension.h>
54#include <zone.h>
55
56
57std::unique_ptr<BOARD_ITEM> CreateGeneratorForType( const wxString& aGeneratorType, BOARD_ITEM_CONTAINER* aContainer )
58{
59 PCB_GENERATOR* generator = GENERATORS_MGR::Instance().CreateFromType( aGeneratorType );
60
61 if( !generator )
62 return nullptr;
63
64 if( aContainer )
65 generator->SetParent( aContainer );
66
67 return std::unique_ptr<BOARD_ITEM>( generator );
68}
69
70
71std::unique_ptr<BOARD_ITEM> CreateItemForType( KICAD_T aType, BOARD_ITEM_CONTAINER* aContainer )
72{
73 switch( aType )
74 {
75 case PCB_TRACE_T: return std::make_unique<PCB_TRACK>( aContainer );
76 case PCB_ARC_T: return std::make_unique<PCB_ARC>( aContainer );
77 case PCB_VIA_T: return std::make_unique<PCB_VIA>( aContainer );
78 case PCB_TEXT_T: return std::make_unique<PCB_TEXT>( aContainer );
79 case PCB_TEXTBOX_T: return std::make_unique<PCB_TEXTBOX>( aContainer );
80 case PCB_TABLE_T: return std::make_unique<PCB_TABLE>( aContainer );
81 case PCB_DRILL_CHART_T: return std::make_unique<PCB_DRILL_CHART>( aContainer );
82 case PCB_DRILL_MAP_T: return std::make_unique<PCB_DRILL_MAP>( aContainer );
83 case PCB_TABLECELL_T:
84 {
85 PCB_TABLE* table = dynamic_cast<PCB_TABLE*>( aContainer );
86
87 if( !table )
88 return nullptr;
89
90 return std::make_unique<PCB_TABLECELL>( aContainer );
91 }
92 case PCB_SHAPE_T: return std::make_unique<PCB_SHAPE>( aContainer );
93 case PCB_POINT_T: return std::make_unique<PCB_POINT>( aContainer );
94 case PCB_BARCODE_T: return std::make_unique<PCB_BARCODE>( aContainer );
95 case PCB_ZONE_T: return std::make_unique<ZONE>( aContainer );
96 case PCB_GROUP_T: return std::make_unique<PCB_GROUP>( aContainer );
97 case PCB_GENERATOR_T: return nullptr; // must be created via CreateGeneratorForType
98 case PCB_CONSTRAINT_T: return std::make_unique<PCB_CONSTRAINT>( aContainer );
99 case PCB_REFERENCE_IMAGE_T: return std::make_unique<PCB_REFERENCE_IMAGE>( aContainer );
100 case PCB_GRID_ITEM_T: return std::make_unique<PCB_GRID_ITEM>( aContainer );
101
102 case PCB_PAD_T:
103 {
104 FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( aContainer );
105
106 if( !footprint )
107 return nullptr;
108
109 return std::make_unique<PAD>( footprint );
110 }
111
112 case PCB_3D_BODY_T:
113 {
114 FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( aContainer );
115
116 if( !footprint )
117 return nullptr;
118
119 return std::make_unique<PCB_3D_BODY>( footprint );
120 }
121
122 case PCB_FIELD_T:
123 {
124 FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( aContainer );
125
126 if( !footprint )
127 return nullptr;
128
129 return std::make_unique<PCB_FIELD>( footprint, FIELD_T::USER );
130 }
131
132 case PCB_FOOTPRINT_T:
133 {
134 BOARD* board = dynamic_cast<BOARD*>( aContainer );
135
136 if( !board )
137 return nullptr;
138
139 return std::make_unique<FOOTPRINT>( board );
140 }
141
142 case PCB_DIM_ALIGNED_T: return std::make_unique<PCB_DIM_ALIGNED>( aContainer );
143 case PCB_DIM_ORTHOGONAL_T: return std::make_unique<PCB_DIM_ORTHOGONAL>( aContainer );
144 case PCB_DIM_RADIAL_T: return std::make_unique<PCB_DIM_RADIAL>( aContainer );
145 case PCB_DIM_LEADER_T: return std::make_unique<PCB_DIM_LEADER>( aContainer );
146 case PCB_DIM_CENTER_T: return std::make_unique<PCB_DIM_CENTER>( aContainer );
147
148 default:
149 return nullptr;
150 }
151}
152
154{
155
156void PackLayerSet( google::protobuf::RepeatedField<int>& aOutput, const LSET& aLayerSet )
157{
158 for( const PCB_LAYER_ID& layer : aLayerSet.Seq() )
159 aOutput.Add( ToProtoEnum<PCB_LAYER_ID, types::BoardLayer>( layer ) );
160}
161
162
163LSET UnpackLayerSet( const google::protobuf::RepeatedField<int>& aProtoLayerSet )
164{
165 LSET set;
166
167 for( int layer : aProtoLayerSet )
168 {
169 wxCHECK2( layer >= F_Cu && layer < PCB_LAYER_ID_COUNT, continue );
170 PCB_LAYER_ID boardLayer =
171 FromProtoEnum<PCB_LAYER_ID>( static_cast<types::BoardLayer>( layer ) );
172
173 if( boardLayer >= 0 && IsValidLayer( boardLayer ) )
174 set.set( boardLayer );
175 }
176
177 return set;
178}
179
180
181void PackBoardStackup( const BOARD& aBoard, BoardStackup& aOut )
182{
183 aBoard.GetStackupOrDefault().Serialize( aOut );
184
185 for( BoardStackupLayer& layer : *aOut.mutable_layers() )
186 {
187 if( layer.type() == BoardStackupLayerType::BSLT_DIELECTRIC )
188 continue;
189
190 PCB_LAYER_ID id = FromProtoEnum<PCB_LAYER_ID>( layer.layer() );
191
192 layer.set_user_name( aBoard.GetLayerName( id ) );
193 }
194}
195
196
197void PackTeardropSettings( types::PadTeardropSettings& aOutput, const TEARDROP_PARAMETERS& aParams )
198{
199 aOutput.set_mode( aParams.m_Enabled ? types::PadTeardropMode::PTM_ENABLED : types::PadTeardropMode::PTM_DISABLED );
200 aOutput.set_curved_edges( aParams.m_CurvedEdges );
201 aOutput.set_allow_multiple_track_segments( aParams.m_AllowUseTwoTracks );
202 aOutput.set_prefer_zone_connection( !aParams.m_TdOnPadsInZones );
203 aOutput.mutable_max_length()->set_value_nm( aParams.m_TdMaxLen );
204 aOutput.mutable_max_width()->set_value_nm( aParams.m_TdMaxWidth );
205 aOutput.set_best_length_ratio( aParams.m_BestLengthRatio );
206 aOutput.set_best_width_ratio( aParams.m_BestWidthRatio );
207 aOutput.set_max_track_width_ratio( aParams.m_WidthtoSizeFilterRatio );
208}
209
210
211void UnpackTeardropSettings( TEARDROP_PARAMETERS& aOutput, const types::PadTeardropSettings& aProto )
212{
213 aOutput.m_Enabled = ( aProto.mode() == types::PadTeardropMode::PTM_ENABLED );
214 aOutput.m_CurvedEdges = aProto.curved_edges();
215 aOutput.m_AllowUseTwoTracks = aProto.allow_multiple_track_segments();
216 aOutput.m_TdOnPadsInZones = !aProto.prefer_zone_connection();
217 aOutput.m_TdMaxLen = aProto.max_length().value_nm();
218 aOutput.m_TdMaxWidth = aProto.max_width().value_nm();
219 aOutput.m_BestLengthRatio = aProto.best_length_ratio();
220 aOutput.m_BestWidthRatio = aProto.best_width_ratio();
221 aOutput.m_WidthtoSizeFilterRatio = aProto.max_track_width_ratio();
222}
223
224
225void PackZoneLayerOverrides( google::protobuf::RepeatedPtrField<types::ZoneLayerOverrideEntry>* aOutput,
226 const std::map<PCB_LAYER_ID, ZONE_LAYER_OVERRIDE>& aInput )
227{
228 aOutput->Clear();
229
230 for( const auto& [layer, overrideVal] : aInput )
231 {
232 types::ZoneLayerOverride protoOverride = types::ZLO_NONE;
233
234 switch( overrideVal )
235 {
236 case ZLO_FORCE_FLASHED: protoOverride = types::ZLO_FORCE_FLASHED; break;
237 case ZLO_FORCE_NO_ZONE_CONNECTION: protoOverride = types::ZLO_FORCE_NO_ZONE_CONNECTION; break;
238 default: break;
239 }
240
241 if( protoOverride != types::ZLO_NONE )
242 {
243 types::ZoneLayerOverrideEntry* entry = aOutput->Add();
244 entry->set_layer( ToProtoEnum<PCB_LAYER_ID, types::BoardLayer>( layer ) );
245 entry->set_override( protoOverride );
246 }
247 }
248}
249
250
251void UnpackZoneLayerOverrides( std::map<PCB_LAYER_ID, ZONE_LAYER_OVERRIDE>& aOutput,
252 const google::protobuf::RepeatedPtrField<types::ZoneLayerOverrideEntry>& aInput )
253{
254 for( const types::ZoneLayerOverrideEntry& entry : aInput )
255 {
256 ZONE_LAYER_OVERRIDE overrideVal = ZLO_NONE;
257
258 switch( entry.override() )
259 {
260 case types::ZLO_FORCE_FLASHED: overrideVal = ZLO_FORCE_FLASHED; break;
261 case types::ZLO_FORCE_NO_ZONE_CONNECTION: overrideVal = ZLO_FORCE_NO_ZONE_CONNECTION; break;
262 default: break;
263 }
264
265 aOutput[FromProtoEnum<PCB_LAYER_ID>( entry.layer() )] = overrideVal;
266 }
267}
268
269
270void PackEmbeddedFiles( common::types::EmbeddedFiles& aOutput, const EMBEDDED_FILES& aFiles )
271{
272 for( const auto& [name, file] : aFiles.EmbeddedFileMap() )
273 {
274 if( file->compressedEncodedData.empty() )
275 continue;
276
277 common::types::EmbeddedFile* proto = aOutput.add_files();
278 proto->set_name( name.ToUTF8() );
279 proto->set_type(
281 proto->set_data( file->compressedEncodedData );
282 proto->set_data_hash( file->data_hash );
283 }
284}
285
286
287bool UnpackEmbeddedFiles( EMBEDDED_FILES& aOutput, const common::types::EmbeddedFiles& aProto )
288{
289 EMBEDDED_FILES files;
290
291 for( const common::types::EmbeddedFile& protoFile : aProto.files() )
292 {
293 auto file = std::make_shared<EMBEDDED_FILES::EMBEDDED_FILE>();
294 file->name = wxString::FromUTF8( protoFile.name() );
295 file->type = FromProtoEnum<EMBEDDED_FILES::EMBEDDED_FILE::FILE_TYPE>( protoFile.type() );
296 file->compressedEncodedData = protoFile.data();
297 file->data_hash = protoFile.data_hash();
298
299 if( EMBEDDED_FILES::DecompressAndDecode( *file, /* aAllowEmptyHash = */ true )
301 {
302 return false;
303 }
304
305 if( !file->Validate() )
306 return false;
307
308 files.AddFile( file );
309 }
310
311 bool embedFonts = aOutput.GetAreFontsEmbedded();
312 aOutput.ClearEmbeddedFiles();
313 aOutput = files;
314 aOutput.SetAreFontsEmbedded( embedFonts );
315
316 return true;
317}
318
319
320std::vector<BOARD_ITEM*> FindItemsFromSyncSelection(
321 const BOARD* aBoard,
322 const google::protobuf::RepeatedPtrField<kiapi::common::commands::SelectionSpec>& aItems )
323{
324 using kiapi::common::commands::SelectionSpec;
325
326 std::vector<std::pair<int, BOARD_ITEM*>> orderPairs;
327 wxCHECK( aBoard, {} );
328
329 // Unpacking rebuilds a KIID per path element, so do it once rather than per footprint
330 std::vector<KIID_PATH> sheetPaths( aItems.size() );
331
332 for( int index = 0; index < aItems.size(); ++index )
333 {
334 if( aItems[index].spec_case() == SelectionSpec::SpecCase::kSheetPath )
335 sheetPaths[index] = kiapi::common::UnpackSheetPath( aItems[index].sheet_path() );
336 }
337
338 for( FOOTPRINT* footprint : aBoard->Footprints() )
339 {
340 wxString fpRef = footprint->GetReference();
341
342 for( int index = 0; index < aItems.size(); ++index )
343 {
344 const SelectionSpec& spec = aItems[index];
345
346 switch( spec.spec_case() )
347 {
348 case SelectionSpec::SpecCase::kFootprint:
349 {
350 if( fpRef == wxString::FromUTF8( spec.footprint().reference() ) )
351 orderPairs.emplace_back( index, footprint );
352
353 break;
354 }
355
356 case SelectionSpec::SpecCase::kPad:
357 {
358 if( fpRef == wxString::FromUTF8( spec.pad().reference() ) )
359 {
360 wxString padNumber = wxString::FromUTF8( spec.pad().number() );
361
362 for( PAD* pad : footprint->Pads() )
363 {
364 if( padNumber == pad->GetNumber() )
365 orderPairs.emplace_back( index, pad );
366 }
367 }
368
369 break;
370 }
371
372 case SelectionSpec::SpecCase::kSheetPath:
373 {
374 if( footprint->IsWithinSchematicSheet( sheetPaths[index] ) )
375 orderPairs.emplace_back( index, footprint );
376
377 break;
378 }
379
380 default: break;
381 }
382 }
383 }
384
385 std::ranges::sort( orderPairs,
386 []( const std::pair<int, BOARD_ITEM*>& a, const std::pair<int, BOARD_ITEM*>& b ) -> bool
387 {
388 return a.first < b.first;
389 } );
390
391 std::vector<BOARD_ITEM*> items;
392 items.reserve( orderPairs.size() );
393
394 for( BOARD_ITEM* val : orderPairs | std::views::values )
395 items.push_back( val );
396
397 return items;
398}
399
400} // namespace kiapi::board
int index
const char * name
KICOMMON_API types::KiCadObjectType ToProtoEnum(KICAD_T aValue)
KICOMMON_API KICAD_T FromProtoEnum(types::KiCadObjectType aValue)
Definition api_enums.cpp:55
std::unique_ptr< BOARD_ITEM > CreateGeneratorForType(const wxString &aGeneratorType, BOARD_ITEM_CONTAINER *aContainer)
std::unique_ptr< BOARD_ITEM > CreateItemForType(KICAD_T aType, BOARD_ITEM_CONTAINER *aContainer)
ZONE_LAYER_OVERRIDE
Conditionally flashed vias and pads that interact with zones of different priority can be very squirr...
Definition board_item.h:73
@ ZLO_NONE
Definition board_item.h:74
@ ZLO_FORCE_NO_ZONE_CONNECTION
Definition board_item.h:76
@ ZLO_FORCE_FLASHED
Definition board_item.h:75
BASE_SET & set(size_t pos)
Definition base_set.h:126
Abstract interface for BOARD_ITEMs capable of storing other items inside.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:85
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:411
BOARD_STACKUP GetStackupOrDefault() const
Definition board.cpp:3459
const FOOTPRINTS & Footprints() const
Definition board.h:465
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition board.cpp:932
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.cpp:153
static RETURN_CODE DecompressAndDecode(EMBEDDED_FILE &aFile, bool aAllowEmptyHash=false)
Takes data from the compressedEncodedData buffer and Base64 decodes it.
void ClearEmbeddedFiles(bool aDeleteFiles=true)
EMBEDDED_FILE * AddFile(const wxFileName &aName, bool aOverwrite)
Load a file from disk and adds it to the collection.
const std::map< wxString, std::shared_ptr< EMBEDDED_FILE > > & EmbeddedFileMap() const
Provide an iterable view of the file collection.
void SetAreFontsEmbedded(bool aEmbedFonts)
bool GetAreFontsEmbedded() const
PCB_GENERATOR * CreateFromType(const wxString &aTypeStr)
static GENERATORS_MGR & Instance()
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition lset.cpp:309
Definition pad.h:61
TEARDROP_PARAMETARS is a helper class to handle parameters needed to build teardrops for a board thes...
double m_BestWidthRatio
The height of a teardrop as ratio between height and size of pad/via.
int m_TdMaxLen
max allowed length for teardrops in IU. <= 0 to disable
bool m_AllowUseTwoTracks
True to create teardrops using 2 track segments if the first in too small.
int m_TdMaxWidth
max allowed height for teardrops in IU. <= 0 to disable
double m_BestLengthRatio
The length of a teardrop as ratio between length and size of pad/via.
double m_WidthtoSizeFilterRatio
The ratio (H/D) between the via/pad size and the track width max value to create a teardrop 1....
bool m_TdOnPadsInZones
A filter to exclude pads inside zone fills.
bool m_Enabled
Flag to enable teardrops.
bool m_CurvedEdges
True if the teardrop should be curved.
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ PCB_LAYER_ID_COUNT
Definition layer_ids.h:167
@ F_Cu
Definition layer_ids.h:60
bool IsValidLayer(int aLayerId)
Test whether a given integer is a valid layer index, i.e.
Definition layer_ids.h:719
void PackLayerSet(google::protobuf::RepeatedField< int > &aOutput, const LSET &aLayerSet)
void PackBoardStackup(const BOARD &aBoard, BoardStackup &aOut)
void PackEmbeddedFiles(common::types::EmbeddedFiles &aOutput, const EMBEDDED_FILES &aFiles)
void PackZoneLayerOverrides(google::protobuf::RepeatedPtrField< types::ZoneLayerOverrideEntry > *aOutput, const std::map< PCB_LAYER_ID, ZONE_LAYER_OVERRIDE > &aInput)
void UnpackTeardropSettings(TEARDROP_PARAMETERS &aOutput, const types::PadTeardropSettings &aProto)
bool UnpackEmbeddedFiles(EMBEDDED_FILES &aOutput, const common::types::EmbeddedFiles &aProto)
LSET UnpackLayerSet(const google::protobuf::RepeatedField< int > &aProtoLayerSet)
std::vector< BOARD_ITEM * > FindItemsFromSyncSelection(const BOARD *aBoard, const google::protobuf::RepeatedPtrField< kiapi::common::commands::SelectionSpec > &aItems)
Resolve a cross-probe selection request against a board.
void UnpackZoneLayerOverrides(std::map< PCB_LAYER_ID, ZONE_LAYER_OVERRIDE > &aOutput, const google::protobuf::RepeatedPtrField< types::ZoneLayerOverrideEntry > &aInput)
void PackTeardropSettings(types::PadTeardropSettings &aOutput, const TEARDROP_PARAMETERS &aParams)
KICOMMON_API KIID_PATH UnpackSheetPath(const types::SheetPath &aInput)
BARCODE class definition.
Class to handle a set of BOARD_ITEMs.
@ USER
The field ID hasn't been set yet; field is invalid.
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:70
@ PCB_CONSTRAINT_T
a geometric constraint between board items
Definition typeinfo.h:237
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition typeinfo.h:80
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition typeinfo.h:98
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition typeinfo.h:95
@ PCB_GENERATOR_T
class PCB_GENERATOR, generator on a layer
Definition typeinfo.h:83
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:89
@ PCB_DRILL_MAP_T
class PCB_DRILL_MAP, drill symbols drawn at the holes
Definition typeinfo.h:240
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition typeinfo.h:96
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition typeinfo.h:103
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition typeinfo.h:85
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition typeinfo.h:100
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition typeinfo.h:84
@ PCB_3D_BODY_T
class PCB_3D_BODY, a 3D body (extruded or model) on a footprint
Definition typeinfo.h:241
@ PCB_REFERENCE_IMAGE_T
class PCB_REFERENCE_IMAGE, bitmap on a layer
Definition typeinfo.h:81
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
Definition typeinfo.h:82
@ PCB_BARCODE_T
class PCB_BARCODE, a barcode (graphic item)
Definition typeinfo.h:93
@ PCB_TABLECELL_T
class PCB_TABLECELL, PCB_TEXTBOX for use in tables
Definition typeinfo.h:87
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition typeinfo.h:78
@ PCB_GRID_ITEM_T
a subgrid placed on a board
Definition typeinfo.h:238
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition typeinfo.h:94
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:79
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition typeinfo.h:90
@ PCB_TABLE_T
class PCB_TABLE, table of PCB_TABLECELLs
Definition typeinfo.h:86
@ PCB_POINT_T
class PCB_POINT, a 0-dimensional point
Definition typeinfo.h:105
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition typeinfo.h:88
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition typeinfo.h:97
@ PCB_DRILL_CHART_T
class PCB_DRILL_CHART, a live drill chart derived from PCB_TABLE
Definition typeinfo.h:239