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_point.h>
45#include <pcb_track.h>
46#include <pcb_field.h>
47#include <pcb_text.h>
48#include <pcb_textbox.h>
49#include <pcb_drill_chart.h>
50#include <pcb_drill_map.h>
51#include <pcb_table.h>
52#include <pcb_dimension.h>
53#include <zone.h>
54
55
56std::unique_ptr<BOARD_ITEM> CreateGeneratorForType( const wxString& aGeneratorType, BOARD_ITEM_CONTAINER* aContainer )
57{
58 PCB_GENERATOR* generator = GENERATORS_MGR::Instance().CreateFromType( aGeneratorType );
59
60 if( !generator )
61 return nullptr;
62
63 if( aContainer )
64 generator->SetParent( aContainer );
65
66 return std::unique_ptr<BOARD_ITEM>( generator );
67}
68
69
70std::unique_ptr<BOARD_ITEM> CreateItemForType( KICAD_T aType, BOARD_ITEM_CONTAINER* aContainer )
71{
72 switch( aType )
73 {
74 case PCB_TRACE_T: return std::make_unique<PCB_TRACK>( aContainer );
75 case PCB_ARC_T: return std::make_unique<PCB_ARC>( aContainer );
76 case PCB_VIA_T: return std::make_unique<PCB_VIA>( aContainer );
77 case PCB_TEXT_T: return std::make_unique<PCB_TEXT>( aContainer );
78 case PCB_TEXTBOX_T: return std::make_unique<PCB_TEXTBOX>( aContainer );
79 case PCB_TABLE_T: return std::make_unique<PCB_TABLE>( aContainer );
80 case PCB_DRILL_CHART_T: return std::make_unique<PCB_DRILL_CHART>( aContainer );
81 case PCB_DRILL_MAP_T: return std::make_unique<PCB_DRILL_MAP>( aContainer );
82 case PCB_TABLECELL_T:
83 {
84 PCB_TABLE* table = dynamic_cast<PCB_TABLE*>( aContainer );
85
86 if( !table )
87 return nullptr;
88
89 return std::make_unique<PCB_TABLECELL>( aContainer );
90 }
91 case PCB_SHAPE_T: return std::make_unique<PCB_SHAPE>( aContainer );
92 case PCB_POINT_T: return std::make_unique<PCB_POINT>( aContainer );
93 case PCB_BARCODE_T: return std::make_unique<PCB_BARCODE>( aContainer );
94 case PCB_ZONE_T: return std::make_unique<ZONE>( aContainer );
95 case PCB_GROUP_T: return std::make_unique<PCB_GROUP>( aContainer );
96 case PCB_GENERATOR_T: return nullptr; // must be created via CreateGeneratorForType
97 case PCB_CONSTRAINT_T: return std::make_unique<PCB_CONSTRAINT>( aContainer );
98 case PCB_REFERENCE_IMAGE_T: return std::make_unique<PCB_REFERENCE_IMAGE>( aContainer );
99 case PCB_GRID_ITEM_T: return std::make_unique<PCB_GRID_ITEM>( aContainer );
100
101 case PCB_PAD_T:
102 {
103 FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( aContainer );
104
105 if( !footprint )
106 return nullptr;
107
108 return std::make_unique<PAD>( footprint );
109 }
110
111 case PCB_FIELD_T:
112 {
113 FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( aContainer );
114
115 if( !footprint )
116 return nullptr;
117
118 return std::make_unique<PCB_FIELD>( footprint, FIELD_T::USER );
119 }
120
121 case PCB_FOOTPRINT_T:
122 {
123 BOARD* board = dynamic_cast<BOARD*>( aContainer );
124
125 if( !board )
126 return nullptr;
127
128 return std::make_unique<FOOTPRINT>( board );
129 }
130
131 case PCB_DIM_ALIGNED_T: return std::make_unique<PCB_DIM_ALIGNED>( aContainer );
132 case PCB_DIM_ORTHOGONAL_T: return std::make_unique<PCB_DIM_ORTHOGONAL>( aContainer );
133 case PCB_DIM_RADIAL_T: return std::make_unique<PCB_DIM_RADIAL>( aContainer );
134 case PCB_DIM_LEADER_T: return std::make_unique<PCB_DIM_LEADER>( aContainer );
135 case PCB_DIM_CENTER_T: return std::make_unique<PCB_DIM_CENTER>( aContainer );
136
137 default:
138 return nullptr;
139 }
140}
141
143{
144
145void PackLayerSet( google::protobuf::RepeatedField<int>& aOutput, const LSET& aLayerSet )
146{
147 for( const PCB_LAYER_ID& layer : aLayerSet.Seq() )
148 aOutput.Add( ToProtoEnum<PCB_LAYER_ID, types::BoardLayer>( layer ) );
149}
150
151
152LSET UnpackLayerSet( const google::protobuf::RepeatedField<int>& aProtoLayerSet )
153{
154 LSET set;
155
156 for( int layer : aProtoLayerSet )
157 {
158 wxCHECK2( layer >= F_Cu && layer < PCB_LAYER_ID_COUNT, continue );
159 PCB_LAYER_ID boardLayer =
160 FromProtoEnum<PCB_LAYER_ID>( static_cast<types::BoardLayer>( layer ) );
161
162 if( boardLayer >= 0 && IsValidLayer( boardLayer ) )
163 set.set( boardLayer );
164 }
165
166 return set;
167}
168
169
170void PackBoardStackup( const BOARD& aBoard, BoardStackup& aOut )
171{
172 aBoard.GetStackupOrDefault().Serialize( aOut );
173
174 for( BoardStackupLayer& layer : *aOut.mutable_layers() )
175 {
176 if( layer.type() == BoardStackupLayerType::BSLT_DIELECTRIC )
177 continue;
178
179 PCB_LAYER_ID id = FromProtoEnum<PCB_LAYER_ID>( layer.layer() );
180
181 layer.set_user_name( aBoard.GetLayerName( id ) );
182 }
183}
184
185
186void PackTeardropSettings( types::PadTeardropSettings& aOutput, const TEARDROP_PARAMETERS& aParams )
187{
188 aOutput.set_mode( aParams.m_Enabled ? types::PadTeardropMode::PTM_ENABLED : types::PadTeardropMode::PTM_DISABLED );
189 aOutput.set_curved_edges( aParams.m_CurvedEdges );
190 aOutput.set_allow_multiple_track_segments( aParams.m_AllowUseTwoTracks );
191 aOutput.set_prefer_zone_connection( !aParams.m_TdOnPadsInZones );
192 aOutput.mutable_max_length()->set_value_nm( aParams.m_TdMaxLen );
193 aOutput.mutable_max_width()->set_value_nm( aParams.m_TdMaxWidth );
194 aOutput.set_best_length_ratio( aParams.m_BestLengthRatio );
195 aOutput.set_best_width_ratio( aParams.m_BestWidthRatio );
196 aOutput.set_max_track_width_ratio( aParams.m_WidthtoSizeFilterRatio );
197}
198
199
200void UnpackTeardropSettings( TEARDROP_PARAMETERS& aOutput, const types::PadTeardropSettings& aProto )
201{
202 aOutput.m_Enabled = ( aProto.mode() == types::PadTeardropMode::PTM_ENABLED );
203 aOutput.m_CurvedEdges = aProto.curved_edges();
204 aOutput.m_AllowUseTwoTracks = aProto.allow_multiple_track_segments();
205 aOutput.m_TdOnPadsInZones = !aProto.prefer_zone_connection();
206 aOutput.m_TdMaxLen = aProto.max_length().value_nm();
207 aOutput.m_TdMaxWidth = aProto.max_width().value_nm();
208 aOutput.m_BestLengthRatio = aProto.best_length_ratio();
209 aOutput.m_BestWidthRatio = aProto.best_width_ratio();
210 aOutput.m_WidthtoSizeFilterRatio = aProto.max_track_width_ratio();
211}
212
213
214void PackZoneLayerOverrides( google::protobuf::RepeatedPtrField<types::ZoneLayerOverrideEntry>* aOutput,
215 const std::map<PCB_LAYER_ID, ZONE_LAYER_OVERRIDE>& aInput )
216{
217 aOutput->Clear();
218
219 for( const auto& [layer, overrideVal] : aInput )
220 {
221 types::ZoneLayerOverride protoOverride = types::ZLO_NONE;
222
223 switch( overrideVal )
224 {
225 case ZLO_FORCE_FLASHED: protoOverride = types::ZLO_FORCE_FLASHED; break;
226 case ZLO_FORCE_NO_ZONE_CONNECTION: protoOverride = types::ZLO_FORCE_NO_ZONE_CONNECTION; break;
227 default: break;
228 }
229
230 if( protoOverride != types::ZLO_NONE )
231 {
232 types::ZoneLayerOverrideEntry* entry = aOutput->Add();
233 entry->set_layer( ToProtoEnum<PCB_LAYER_ID, types::BoardLayer>( layer ) );
234 entry->set_override( protoOverride );
235 }
236 }
237}
238
239
240void UnpackZoneLayerOverrides( std::map<PCB_LAYER_ID, ZONE_LAYER_OVERRIDE>& aOutput,
241 const google::protobuf::RepeatedPtrField<types::ZoneLayerOverrideEntry>& aInput )
242{
243 for( const types::ZoneLayerOverrideEntry& entry : aInput )
244 {
245 ZONE_LAYER_OVERRIDE overrideVal = ZLO_NONE;
246
247 switch( entry.override() )
248 {
249 case types::ZLO_FORCE_FLASHED: overrideVal = ZLO_FORCE_FLASHED; break;
250 case types::ZLO_FORCE_NO_ZONE_CONNECTION: overrideVal = ZLO_FORCE_NO_ZONE_CONNECTION; break;
251 default: break;
252 }
253
254 aOutput[FromProtoEnum<PCB_LAYER_ID>( entry.layer() )] = overrideVal;
255 }
256}
257
258
259void PackEmbeddedFiles( common::types::EmbeddedFiles& aOutput, const EMBEDDED_FILES& aFiles )
260{
261 for( const auto& [name, file] : aFiles.EmbeddedFileMap() )
262 {
263 if( file->compressedEncodedData.empty() )
264 continue;
265
266 common::types::EmbeddedFile* proto = aOutput.add_files();
267 proto->set_name( name.ToUTF8() );
268 proto->set_type(
270 proto->set_data( file->compressedEncodedData );
271 proto->set_data_hash( file->data_hash );
272 }
273}
274
275
276bool UnpackEmbeddedFiles( EMBEDDED_FILES& aOutput, const common::types::EmbeddedFiles& aProto )
277{
278 EMBEDDED_FILES files;
279
280 for( const common::types::EmbeddedFile& protoFile : aProto.files() )
281 {
282 auto file = std::make_shared<EMBEDDED_FILES::EMBEDDED_FILE>();
283 file->name = wxString::FromUTF8( protoFile.name() );
284 file->type = FromProtoEnum<EMBEDDED_FILES::EMBEDDED_FILE::FILE_TYPE>( protoFile.type() );
285 file->compressedEncodedData = protoFile.data();
286 file->data_hash = protoFile.data_hash();
287
288 if( EMBEDDED_FILES::DecompressAndDecode( *file, /* aAllowEmptyHash = */ true )
290 {
291 return false;
292 }
293
294 if( !file->Validate() )
295 return false;
296
297 files.AddFile( file );
298 }
299
300 bool embedFonts = aOutput.GetAreFontsEmbedded();
301 aOutput.ClearEmbeddedFiles();
302 aOutput = files;
303 aOutput.SetAreFontsEmbedded( embedFonts );
304
305 return true;
306}
307
308
309std::vector<BOARD_ITEM*> FindItemsFromSyncSelection(
310 const BOARD* aBoard,
311 const google::protobuf::RepeatedPtrField<kiapi::common::commands::SelectionSpec>& aItems )
312{
313 using kiapi::common::commands::SelectionSpec;
314
315 std::vector<std::pair<int, BOARD_ITEM*>> orderPairs;
316 wxCHECK( aBoard, {} );
317
318 // Unpacking rebuilds a KIID per path element, so do it once rather than per footprint
319 std::vector<KIID_PATH> sheetPaths( aItems.size() );
320
321 for( int index = 0; index < aItems.size(); ++index )
322 {
323 if( aItems[index].spec_case() == SelectionSpec::SpecCase::kSheetPath )
324 sheetPaths[index] = kiapi::common::UnpackSheetPath( aItems[index].sheet_path() );
325 }
326
327 for( FOOTPRINT* footprint : aBoard->Footprints() )
328 {
329 wxString fpRef = footprint->GetReference();
330
331 for( int index = 0; index < aItems.size(); ++index )
332 {
333 const SelectionSpec& spec = aItems[index];
334
335 switch( spec.spec_case() )
336 {
337 case SelectionSpec::SpecCase::kFootprint:
338 {
339 if( fpRef == wxString::FromUTF8( spec.footprint().reference() ) )
340 orderPairs.emplace_back( index, footprint );
341
342 break;
343 }
344
345 case SelectionSpec::SpecCase::kPad:
346 {
347 if( fpRef == wxString::FromUTF8( spec.pad().reference() ) )
348 {
349 wxString padNumber = wxString::FromUTF8( spec.pad().number() );
350
351 for( PAD* pad : footprint->Pads() )
352 {
353 if( padNumber == pad->GetNumber() )
354 orderPairs.emplace_back( index, pad );
355 }
356 }
357
358 break;
359 }
360
361 case SelectionSpec::SpecCase::kSheetPath:
362 {
363 if( footprint->IsWithinSchematicSheet( sheetPaths[index] ) )
364 orderPairs.emplace_back( index, footprint );
365
366 break;
367 }
368
369 default: break;
370 }
371 }
372 }
373
374 std::ranges::sort( orderPairs,
375 []( const std::pair<int, BOARD_ITEM*>& a, const std::pair<int, BOARD_ITEM*>& b ) -> bool
376 {
377 return a.first < b.first;
378 } );
379
380 std::vector<BOARD_ITEM*> items;
381 items.reserve( orderPairs.size() );
382
383 for( BOARD_ITEM* val : orderPairs | std::views::values )
384 items.push_back( val );
385
386 return items;
387}
388
389} // 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:72
@ ZLO_NONE
Definition board_item.h:73
@ ZLO_FORCE_NO_ZONE_CONNECTION
Definition board_item.h:75
@ ZLO_FORCE_FLASHED
Definition board_item.h:74
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:84
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:410
BOARD_STACKUP GetStackupOrDefault() const
Definition board.cpp:3660
const FOOTPRINTS & Footprints() const
Definition board.h:464
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition board.cpp:943
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:681
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_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