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