KiCad PCB EDA Suite
Loading...
Searching...
No Matches
altium_parser_pcb.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) 2020 Thomas Pointhuber <[email protected]>
5 * Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU 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, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25#include <map>
26#include <unordered_map>
27
28#include <ki_exception.h>
29#include <math/util.h>
30
31#include <wx/log.h>
32
33#include "altium_parser_pcb.h"
35
36
37ALTIUM_LAYER altium_layer_from_name( const wxString& aName )
38{
39 static const std::unordered_map<std::string, ALTIUM_LAYER> hash_map = {
40 { "TOP", ALTIUM_LAYER::TOP_LAYER },
41 { "MID1", ALTIUM_LAYER::MID_LAYER_1 },
42 { "MID2", ALTIUM_LAYER::MID_LAYER_2 },
43 { "MID3", ALTIUM_LAYER::MID_LAYER_3 },
44 { "MID4", ALTIUM_LAYER::MID_LAYER_4 },
45 { "MID5", ALTIUM_LAYER::MID_LAYER_5 },
46 { "MID6", ALTIUM_LAYER::MID_LAYER_6 },
47 { "MID7", ALTIUM_LAYER::MID_LAYER_7 },
48 { "MID8", ALTIUM_LAYER::MID_LAYER_8 },
49 { "MID9", ALTIUM_LAYER::MID_LAYER_9 },
50 { "MID10", ALTIUM_LAYER::MID_LAYER_10 },
51 { "MID11", ALTIUM_LAYER::MID_LAYER_11 },
52 { "MID12", ALTIUM_LAYER::MID_LAYER_12 },
53 { "MID13", ALTIUM_LAYER::MID_LAYER_13 },
54 { "MID14", ALTIUM_LAYER::MID_LAYER_14 },
55 { "MID15", ALTIUM_LAYER::MID_LAYER_15 },
56 { "MID16", ALTIUM_LAYER::MID_LAYER_16 },
57 { "MID17", ALTIUM_LAYER::MID_LAYER_17 },
58 { "MID18", ALTIUM_LAYER::MID_LAYER_18 },
59 { "MID19", ALTIUM_LAYER::MID_LAYER_19 },
60 { "MID20", ALTIUM_LAYER::MID_LAYER_20 },
61 { "MID21", ALTIUM_LAYER::MID_LAYER_21 },
62 { "MID22", ALTIUM_LAYER::MID_LAYER_22 },
63 { "MID23", ALTIUM_LAYER::MID_LAYER_23 },
64 { "MID24", ALTIUM_LAYER::MID_LAYER_24 },
65 { "MID25", ALTIUM_LAYER::MID_LAYER_25 },
66 { "MID26", ALTIUM_LAYER::MID_LAYER_26 },
67 { "MID27", ALTIUM_LAYER::MID_LAYER_27 },
68 { "MID28", ALTIUM_LAYER::MID_LAYER_28 },
69 { "MID29", ALTIUM_LAYER::MID_LAYER_29 },
70 { "MID30", ALTIUM_LAYER::MID_LAYER_30 },
71 { "BOTTOM", ALTIUM_LAYER::BOTTOM_LAYER },
72
73 { "TOPOVERLAY", ALTIUM_LAYER::TOP_OVERLAY },
74 { "BOTTOMOVERLAY", ALTIUM_LAYER::BOTTOM_OVERLAY },
75 { "TOPPASTE", ALTIUM_LAYER::TOP_PASTE },
76 { "BOTTOMPASTE", ALTIUM_LAYER::BOTTOM_PASTE },
77 { "TOPSOLDER", ALTIUM_LAYER::TOP_SOLDER },
78 { "BOTTOMSOLDER", ALTIUM_LAYER::BOTTOM_SOLDER },
79
96
97 { "DRILLGUIDE", ALTIUM_LAYER::DRILL_GUIDE },
98 { "KEEPOUT", ALTIUM_LAYER::KEEP_OUT_LAYER },
99
100 { "MECHANICAL1", ALTIUM_LAYER::MECHANICAL_1 },
101 { "MECHANICAL2", ALTIUM_LAYER::MECHANICAL_2 },
102 { "MECHANICAL3", ALTIUM_LAYER::MECHANICAL_3 },
103 { "MECHANICAL4", ALTIUM_LAYER::MECHANICAL_4 },
104 { "MECHANICAL5", ALTIUM_LAYER::MECHANICAL_5 },
105 { "MECHANICAL6", ALTIUM_LAYER::MECHANICAL_6 },
106 { "MECHANICAL7", ALTIUM_LAYER::MECHANICAL_7 },
107 { "MECHANICAL8", ALTIUM_LAYER::MECHANICAL_8 },
108 { "MECHANICAL9", ALTIUM_LAYER::MECHANICAL_9 },
109 { "MECHANICAL10", ALTIUM_LAYER::MECHANICAL_10 },
110 { "MECHANICAL11", ALTIUM_LAYER::MECHANICAL_11 },
111 { "MECHANICAL12", ALTIUM_LAYER::MECHANICAL_12 },
112 { "MECHANICAL13", ALTIUM_LAYER::MECHANICAL_13 },
113 { "MECHANICAL14", ALTIUM_LAYER::MECHANICAL_14 },
114 { "MECHANICAL15", ALTIUM_LAYER::MECHANICAL_15 },
115 { "MECHANICAL16", ALTIUM_LAYER::MECHANICAL_16 },
116
117 { "DRILLDRAWING", ALTIUM_LAYER::DRILL_DRAWING },
118 { "MULTILAYER", ALTIUM_LAYER::MULTI_LAYER },
119
120 // FIXME: the following mapping is just a guess
121 { "CONNECTIONS", ALTIUM_LAYER::CONNECTIONS },
122 { "BACKGROUND", ALTIUM_LAYER::BACKGROUND },
123 { "DRCERRORMARKERS", ALTIUM_LAYER::DRC_ERROR_MARKERS },
124 { "SELECTIONS", ALTIUM_LAYER::SELECTIONS },
125 { "VISIBLEGRID1", ALTIUM_LAYER::VISIBLE_GRID_1 },
126 { "VISIBLEGRID2", ALTIUM_LAYER::VISIBLE_GRID_2 },
127 { "PADHOLES", ALTIUM_LAYER::PAD_HOLES },
128 { "VIAHOLES", ALTIUM_LAYER::VIA_HOLES },
129 };
130
131 auto it = hash_map.find( std::string( aName.c_str() ) );
132
133 if( it == hash_map.end() )
134 {
135 wxLogError( _( "Unknown mapping of the Altium layer '%s'." ), aName );
137 }
138 else
139 {
140 return it->second;
141 }
142}
143
144void altium_parse_polygons( std::map<wxString, wxString>& aProps,
145 std::vector<ALTIUM_VERTICE>& aVertices )
146{
147 for( size_t i = 0; i < std::numeric_limits<size_t>::max(); i++ )
148 {
149 const wxString si = std::to_string( i );
150
151 const wxString vxi = wxT( "VX" ) + si;
152 const wxString vyi = wxT( "VY" ) + si;
153
154 if( aProps.find( vxi ) == aProps.end() || aProps.find( vyi ) == aProps.end() )
155 break; // it doesn't seem like we know beforehand how many vertices are inside a polygon
156
157 const bool isRound = ALTIUM_PARSER::ReadInt( aProps, wxT( "KIND" ) + si, 0 ) != 0;
158 const int32_t radius = ALTIUM_PARSER::ReadKicadUnit( aProps, wxT( "R" ) + si, wxT( "0mil" ) );
159 const double sa = ALTIUM_PARSER::ReadDouble( aProps, wxT( "SA" ) + si, 0. );
160 const double ea = ALTIUM_PARSER::ReadDouble( aProps, wxT( "EA" ) + si, 0. );
161 const VECTOR2I vp = VECTOR2I( ALTIUM_PARSER::ReadKicadUnit( aProps, vxi, wxT( "0mil" ) ),
162 -ALTIUM_PARSER::ReadKicadUnit( aProps, vyi, wxT( "0mil" ) ) );
163 const VECTOR2I cp = VECTOR2I( ALTIUM_PARSER::ReadKicadUnit( aProps, wxT( "CX" ) + si, wxT( "0mil" ) ),
164 -ALTIUM_PARSER::ReadKicadUnit( aProps, wxT( "CY" ) + si, wxT( "0mil" ) ) );
165
166 aVertices.emplace_back( isRound, radius, sa, ea, vp, cp );
167 }
168}
169
170
171static ALTIUM_MODE ReadAltiumModeFromProperties( const std::map<wxString, wxString>& aProps,
172 wxString aKey )
173{
174 wxString mode = ALTIUM_PARSER::ReadString( aProps, aKey, wxT( "" ) );
175
176 if( mode == wxT( "None" ) )
177 return ALTIUM_MODE::NONE;
178 else if( mode == wxT( "Rule" ) )
179 return ALTIUM_MODE::RULE;
180 else if( mode == wxT( "Manual" ) )
181 return ALTIUM_MODE::MANUAL;
182
183 wxLogError( _( "Unknown Mode string: '%s'." ), mode );
185}
186
187
188static ALTIUM_RECORD ReadAltiumRecordFromProperties( const std::map<wxString, wxString>& aProps,
189 wxString aKey )
190{
191 wxString record = ALTIUM_PARSER::ReadString( aProps, aKey, wxT( "" ) );
192
193 if( record == wxT( "Arc" ) )
194 return ALTIUM_RECORD::ARC;
195 else if( record == wxT( "Pad" ) )
196 return ALTIUM_RECORD::PAD;
197 else if( record == wxT( "Via" ) )
198 return ALTIUM_RECORD::VIA;
199 else if( record == wxT( "Track" ) )
201 else if( record == wxT( "Text" ) )
202 return ALTIUM_RECORD::TEXT;
203 else if( record == wxT( "Fill" ) )
204 return ALTIUM_RECORD::FILL;
205 else if( record == wxT( "Region" ) ) // correct?
207 else if( record == wxT( "Model" ) )
209
210 wxLogError( _( "Unknown Record name string: '%s'." ), record );
212}
213
214
217 const std::map<wxString, wxString>& aProps, wxString aKey )
218{
219 wxString parsedType = ALTIUM_PARSER::ReadString( aProps, aKey, wxT( "" ) );
220
221 if( parsedType == wxT( "Mask" ) )
223
224 wxLogError( _( "Unknown Extended Primitive Information type: '%s'." ), parsedType );
226}
227
228
230{
231 const std::map<wxString, wxString> props = aReader.ReadProperties();
232
233 if( props.empty() )
234 THROW_IO_ERROR( wxT( "ExtendedPrimitiveInformation stream has no properties!" ) );
235
236 primitiveIndex = ALTIUM_PARSER::ReadInt( props, wxT( "PRIMITIVEINDEX" ), -1 );
237 primitiveObjectId = ReadAltiumRecordFromProperties( props, wxT( "PRIMITIVEOBJECTID" ) );
239
240 pastemaskexpansionmode = ReadAltiumModeFromProperties( props, wxT( "PASTEMASKEXPANSIONMODE" ) );
242 props, wxT( "PASTEMASKEXPANSION_MANUAL" ), wxT( "0mil" ) );
244 ReadAltiumModeFromProperties( props, wxT( "SOLDERMASKEXPANSIONMODE" ) );
246 props, wxT( "SOLDERMASKEXPANSION_MANUAL" ), wxT( "0mil" ) );
247}
248
249
251{
252 std::map<wxString, wxString> props = aReader.ReadProperties();
253
254 if( props.empty() )
255 THROW_IO_ERROR( wxT( "Board6 stream has no properties!" ) );
256
257 sheetpos = VECTOR2I( ALTIUM_PARSER::ReadKicadUnit( props, wxT( "SHEETX" ), wxT( "0mil" ) ),
258 -ALTIUM_PARSER::ReadKicadUnit( props, wxT( "SHEETY" ), wxT( "0mil" ) ) );
259 sheetsize = wxSize( ALTIUM_PARSER::ReadKicadUnit( props, wxT( "SHEETWIDTH" ), wxT( "0mil" ) ),
260 ALTIUM_PARSER::ReadKicadUnit( props, wxT( "SHEETHEIGHT" ), wxT( "0mil" ) ) );
261
262 layercount = ALTIUM_PARSER::ReadInt( props, wxT( "LAYERSETSCOUNT" ), 1 ) + 1;
263
264 for( size_t i = 1; i < std::numeric_limits<size_t>::max(); i++ )
265 {
266 const wxString layeri = wxT( "LAYER" ) + std::to_string( i );
267 const wxString layername = layeri + wxT( "NAME" );
268
269 auto layernameit = props.find( layername );
270
271 if( layernameit == props.end() )
272 break; // it doesn't seem like we know beforehand how many vertices are inside a polygon
273
275
276 l.name = ALTIUM_PARSER::ReadString( props, layername, wxT( "" ) );
277 wxString originalName = l.name;
278 int ii = 2;
279
280 // Ensure that layer names are unique in KiCad
281 while( !layerNames.insert( l.name ).second )
282 l.name = wxString::Format( wxT( "%s %d" ), originalName, ii++ );
283
284 l.nextId = ALTIUM_PARSER::ReadInt( props, layeri + wxT( "NEXT" ), 0 );
285 l.prevId = ALTIUM_PARSER::ReadInt( props, layeri + wxT( "PREV" ), 0 );
286 l.copperthick = ALTIUM_PARSER::ReadKicadUnit( props, layeri + wxT( "COPTHICK" ), wxT( "1.4mil" ) );
287
288 l.dielectricconst = ALTIUM_PARSER::ReadDouble( props, layeri + wxT( "DIELCONST" ), 0. );
289 l.dielectricthick = ALTIUM_PARSER::ReadKicadUnit( props, layeri + wxT( "DIELHEIGHT" ), wxT( "60mil" ) );
290 l.dielectricmaterial = ALTIUM_PARSER::ReadString( props, layeri + wxT( "DIELMATERIAL" ), wxT( "FR-4" ) );
291
292 stackup.push_back( l );
293 }
294
296
297 if( aReader.HasParsingError() )
298 THROW_IO_ERROR( wxT( "Board6 stream was not parsed correctly!" ) );
299}
300
302{
303 std::map<wxString, wxString> properties = aReader.ReadProperties();
304
305 if( properties.empty() )
306 THROW_IO_ERROR( wxT( "Classes6 stream has no properties!" ) );
307
308 name = ALTIUM_PARSER::ReadString( properties, wxT( "NAME" ), wxT( "" ) );
309 uniqueid = ALTIUM_PARSER::ReadString( properties, wxT( "UNIQUEID" ), wxT( "" ) );
310 kind = static_cast<ALTIUM_CLASS_KIND>( ALTIUM_PARSER::ReadInt( properties, wxT( "KIND" ), -1 ) );
311
312 for( size_t i = 0; i < std::numeric_limits<size_t>::max(); i++ )
313 {
314 auto mit = properties.find( wxT( "M" ) + std::to_string( i ) );
315
316 if( mit == properties.end() )
317 break; // it doesn't seem like we know beforehand how many components are in the netclass
318
319 names.push_back( mit->second );
320 }
321
322 if( aReader.HasParsingError() )
323 THROW_IO_ERROR( wxT( "Classes6 stream was not parsed correctly" ) );
324}
325
327{
328 std::map<wxString, wxString> props = aReader.ReadProperties();
329
330 if( props.empty() )
331 THROW_IO_ERROR( wxT( "Components6 stream has no props" ) );
332
333 layer = altium_layer_from_name( ALTIUM_PARSER::ReadString( props, wxT( "LAYER" ), wxT( "" ) ) );
334 position = VECTOR2I( ALTIUM_PARSER::ReadKicadUnit( props, wxT( "X" ), wxT( "0mil" ) ),
335 -ALTIUM_PARSER::ReadKicadUnit( props, wxT( "Y" ), wxT( "0mil" ) ) );
336 rotation = ALTIUM_PARSER::ReadDouble( props, wxT( "ROTATION" ), 0. );
337 locked = ALTIUM_PARSER::ReadBool( props, wxT( "LOCKED" ), false );
338 nameon = ALTIUM_PARSER::ReadBool( props, wxT( "NAMEON" ), true );
339 commenton = ALTIUM_PARSER::ReadBool( props, wxT( "COMMENTON" ), false );
340 sourcedesignator = ALTIUM_PARSER::ReadString( props, wxT( "SOURCEDESIGNATOR" ), wxT( "" ) );
341
343 ALTIUM_PARSER::ReadUnicodeString( props, wxT( "SOURCEFOOTPRINTLIBRARY" ), wxT( "" ) );
344 pattern = ALTIUM_PARSER::ReadUnicodeString( props, wxT( "PATTERN" ), wxT( "" ) );
345
346 sourcecomponentlibrary = ALTIUM_PARSER::ReadString( props, wxT( "SOURCECOMPONENTLIBRARY" ), wxT( "" ) );
347 sourcelibreference = ALTIUM_PARSER::ReadString( props, wxT( "SOURCELIBREFERENCE" ), wxT( "" ) );
348
350 ALTIUM_PARSER::ReadInt( props, wxT( "NAMEAUTOPOSITION" ), 0 ) );
352 ALTIUM_PARSER::ReadInt( props, wxT( "COMMENTAUTOPOSITION" ), 0 ) );
353
354 if( aReader.HasParsingError() )
355 THROW_IO_ERROR( wxT( "Components6 stream was not parsed correctly" ) );
356}
357
359{
360 aReader.Skip( 2 );
361
362 std::map<wxString, wxString> props = aReader.ReadProperties();
363
364 if( props.empty() )
365 THROW_IO_ERROR( wxT( "Dimensions6 stream has no props" ) );
366
367 layer = altium_layer_from_name( ALTIUM_PARSER::ReadString( props, wxT( "LAYER" ), wxT( "" ) ) );
368 kind = static_cast<ALTIUM_DIMENSION_KIND>( ALTIUM_PARSER::ReadInt( props, wxT( "DIMENSIONKIND" ), 0 ) );
369
370 textformat = ALTIUM_PARSER::ReadString( props, wxT( "TEXTFORMAT" ), wxT( "" ) );
371 textprefix = ALTIUM_PARSER::ReadString( props, wxT( "TEXTPREFIX" ), wxT( "" ) );
372 textsuffix = ALTIUM_PARSER::ReadString( props, wxT( "TEXTSUFFIX" ), wxT( "" ) );
373
374 height = ALTIUM_PARSER::ReadKicadUnit( props, wxT( "HEIGHT" ), wxT( "0mil" ) );
375 angle = ALTIUM_PARSER::ReadDouble( props, wxT( "ANGLE" ), 0. );
376
377 linewidth = ALTIUM_PARSER::ReadKicadUnit( props, wxT( "LINEWIDTH" ), wxT( "10mil" ) );
378 textheight = ALTIUM_PARSER::ReadKicadUnit( props, wxT( "TEXTHEIGHT" ), wxT( "10mil" ) );
379 textlinewidth = ALTIUM_PARSER::ReadKicadUnit( props, wxT( "TEXTLINEWIDTH" ), wxT( "6mil" ) );
380 textprecision = ALTIUM_PARSER::ReadInt( props, wxT( "TEXTPRECISION" ), 2 );
381 textbold = ALTIUM_PARSER::ReadBool( props, wxT( "TEXTLINEWIDTH" ), false );
382 textitalic = ALTIUM_PARSER::ReadBool( props, wxT( "ITALIC" ), false );
383 textgap = ALTIUM_PARSER::ReadKicadUnit( props, wxT( "TEXTGAP" ), wxT( "10mil" ) );
384
385 arrowsize = ALTIUM_PARSER::ReadKicadUnit( props, wxT( "ARROWSIZE" ), wxT( "60mil" ) );
386
387 wxString text_position_raw = ALTIUM_PARSER::ReadString( props, wxT( "TEXTPOSITION" ), wxT( "" ) );
388
389 xy1 = VECTOR2I( ALTIUM_PARSER::ReadKicadUnit( props, wxT( "X1" ), wxT( "0mil" ) ),
390 -ALTIUM_PARSER::ReadKicadUnit( props, wxT( "Y1" ), wxT( "0mil" ) ) );
391
392 int refcount = ALTIUM_PARSER::ReadInt( props, wxT( "REFERENCES_COUNT" ), 0 );
393
394 for( int i = 0; i < refcount; i++ )
395 {
396 const std::string refi = "REFERENCE" + std::to_string( i ) + "POINT";
397 referencePoint.emplace_back( ALTIUM_PARSER::ReadKicadUnit( props, refi + wxT( "X" ), wxT( "0mil" ) ),
398 -ALTIUM_PARSER::ReadKicadUnit( props, refi + wxT( "Y" ), wxT( "0mil" ) ) );
399 }
400
401 for( size_t i = 1; i < std::numeric_limits<size_t>::max(); i++ )
402 {
403 const std::string texti = "TEXT" + std::to_string( i );
404 const std::string textix = texti + "X";
405 const std::string textiy = texti + "Y";
406
407 if( props.find( textix ) == props.end() || props.find( textiy ) == props.end() )
408 break; // it doesn't seem like we know beforehand how many vertices are inside a polygon
409
410 textPoint.emplace_back( ALTIUM_PARSER::ReadKicadUnit( props, textix, wxT( "0mil" ) ),
411 -ALTIUM_PARSER::ReadKicadUnit( props, textiy, wxT( "0mil" ) ) );
412 }
413
414 wxString dimensionunit = ALTIUM_PARSER::ReadString( props, wxT( "TEXTDIMENSIONUNIT" ), wxT( "Millimeters" ) );
415
416 if( dimensionunit == wxT( "Inches" ) ) textunit = ALTIUM_UNIT::INCHES;
417 else if( dimensionunit == wxT( "Mils" ) ) textunit = ALTIUM_UNIT::MILS;
418 else if( dimensionunit == wxT( "Millimeters" ) ) textunit = ALTIUM_UNIT::MILLIMETERS;
419 else if( dimensionunit == wxT( "Centimeters" ) ) textunit = ALTIUM_UNIT::CENTIMETER;
420 else textunit = ALTIUM_UNIT::UNKNOWN;
421
422 if( aReader.HasParsingError() )
423 THROW_IO_ERROR( wxT( "Dimensions6 stream was not parsed correctly" ) );
424}
425
427{
428 std::map<wxString, wxString> properties = aReader.ReadProperties();
429
430 if( properties.empty() )
431 THROW_IO_ERROR( wxT( "Model stream has no properties!" ) );
432
433 name = ALTIUM_PARSER::ReadString( properties, wxT( "NAME" ), wxT( "" ) );
434 id = ALTIUM_PARSER::ReadString( properties, wxT( "ID" ), wxT( "" ) );
435 isEmbedded = ALTIUM_PARSER::ReadBool( properties, wxT( "EMBED" ), false );
436
437 rotation.x = ALTIUM_PARSER::ReadDouble( properties, wxT( "ROTX" ), 0. );
438 rotation.y = ALTIUM_PARSER::ReadDouble( properties, wxT( "ROTY" ), 0. );
439 rotation.z = ALTIUM_PARSER::ReadDouble( properties, wxT( "ROTZ" ), 0. );
440
441 if( aReader.HasParsingError() )
442 THROW_IO_ERROR( wxT( "Model stream was not parsed correctly" ) );
443}
444
446{
447 std::map<wxString, wxString> properties = aReader.ReadProperties();
448
449 if( properties.empty() )
450 THROW_IO_ERROR( wxT( "Nets6 stream has no properties" ) );
451
452 name = ALTIUM_PARSER::ReadString( properties, wxT( "NAME" ), wxT( "" ) );
453
454 if( aReader.HasParsingError() )
455 THROW_IO_ERROR( wxT( "Nets6 stream was not parsed correctly" ) );
456}
457
459{
460 std::map<wxString, wxString> properties = aReader.ReadProperties();
461
462 if( properties.empty() )
463 THROW_IO_ERROR( wxT( "Polygons6 stream has no properties" ) );
464
465 layer = altium_layer_from_name( ALTIUM_PARSER::ReadString( properties, wxT( "LAYER" ), wxT( "" ) ) );
466 net = ALTIUM_PARSER::ReadInt( properties, wxT( "NET" ), ALTIUM_NET_UNCONNECTED );
467 locked = ALTIUM_PARSER::ReadBool( properties, wxT( "LOCKED" ), false );
468
469 // TODO: kind
470
471 gridsize = ALTIUM_PARSER::ReadKicadUnit( properties, wxT( "GRIDSIZE" ), wxT( "0mil" ) );
472 trackwidth = ALTIUM_PARSER::ReadKicadUnit( properties, wxT( "TRACKWIDTH" ), wxT( "0mil" ) );
473 minprimlength = ALTIUM_PARSER::ReadKicadUnit( properties, wxT( "MINPRIMLENGTH" ), wxT( "0mil" ) );
474 useoctagons = ALTIUM_PARSER::ReadBool( properties, wxT( "USEOCTAGONS" ), false );
475
476 pourindex = ALTIUM_PARSER::ReadInt( properties, wxT( "POURINDEX" ), 0 );
477
478 wxString hatchstyleraw = ALTIUM_PARSER::ReadString( properties, wxT( "HATCHSTYLE" ), wxT( "" ) );
479
480 if( hatchstyleraw == wxT( "Solid" ) ) hatchstyle = ALTIUM_POLYGON_HATCHSTYLE::SOLID;
481 else if( hatchstyleraw == wxT( "45Degree" ) ) hatchstyle = ALTIUM_POLYGON_HATCHSTYLE::DEGREE_45;
482 else if( hatchstyleraw == wxT( "90Degree" ) ) hatchstyle = ALTIUM_POLYGON_HATCHSTYLE::DEGREE_90;
483 else if( hatchstyleraw == wxT( "Horizontal" ) ) hatchstyle = ALTIUM_POLYGON_HATCHSTYLE::HORIZONTAL;
484 else if( hatchstyleraw == wxT( "Vertical" ) ) hatchstyle = ALTIUM_POLYGON_HATCHSTYLE::VERTICAL;
485 else if( hatchstyleraw == wxT( "None" ) ) hatchstyle = ALTIUM_POLYGON_HATCHSTYLE::NONE;
486 else hatchstyle = ALTIUM_POLYGON_HATCHSTYLE::UNKNOWN;
487
488 altium_parse_polygons( properties, vertices );
489
490 if( aReader.HasParsingError() )
491 THROW_IO_ERROR( wxT( "Polygons6 stream was not parsed correctly" ) );
492}
493
495{
496 // Initialize all variables and make Coverity happy
497 clearanceGap = 0;
502 polygonconnectStyle = ALTIUM_CONNECT_STYLE::UNKNOWN;
503
504 aReader.Skip( 2 );
505
506 std::map<wxString, wxString> props = aReader.ReadProperties();
507
508 if( props.empty() )
509 THROW_IO_ERROR( wxT( "Rules6 stream has no props" ) );
510
511 name = ALTIUM_PARSER::ReadString( props, wxT( "NAME" ), wxT( "" ) );
512 priority = ALTIUM_PARSER::ReadInt( props, wxT( "PRIORITY" ), 1 );
513
514 scope1expr = ALTIUM_PARSER::ReadString( props, wxT( "SCOPE1EXPRESSION" ), wxT( "" ) );
515 scope2expr = ALTIUM_PARSER::ReadString( props, wxT( "SCOPE2EXPRESSION" ), wxT( "" ) );
516
517 wxString rulekind = ALTIUM_PARSER::ReadString( props, wxT( "RULEKIND" ), wxT( "" ) );
518 if( rulekind == wxT( "Clearance" ) )
519 {
520 kind = ALTIUM_RULE_KIND::CLEARANCE;
521 clearanceGap = ALTIUM_PARSER::ReadKicadUnit( props, wxT( "GAP" ), wxT( "10mil" ) );
522 }
523 else if( rulekind == wxT( "DiffPairsRouting" ) )
524 {
525 kind = ALTIUM_RULE_KIND::DIFF_PAIR_ROUTINGS;
526 }
527 else if( rulekind == wxT( "Height" ) )
528 {
529 kind = ALTIUM_RULE_KIND::HEIGHT;
530 }
531 else if( rulekind == wxT( "HoleSize" ) )
532 {
533 kind = ALTIUM_RULE_KIND::HOLE_SIZE;
534 }
535 else if( rulekind == wxT( "HoleToHoleClearance" ) )
536 {
537 kind = ALTIUM_RULE_KIND::HOLE_TO_HOLE_CLEARANCE;
538 }
539 else if( rulekind == wxT( "Width" ) )
540 {
541 kind = ALTIUM_RULE_KIND::WIDTH;
542 }
543 else if( rulekind == wxT( "PasteMaskExpansion" ) )
544 {
545 kind = ALTIUM_RULE_KIND::PASTE_MASK_EXPANSION;
546 pastemaskExpansion = ALTIUM_PARSER::ReadKicadUnit( props, wxT( "EXPANSION" ), wxT( "0" ) );
547 }
548 else if( rulekind == wxT( "SolderMaskExpansion" ) )
549 {
550 kind = ALTIUM_RULE_KIND::SOLDER_MASK_EXPANSION;
552 ALTIUM_PARSER::ReadKicadUnit( props, wxT( "EXPANSION" ), wxT( "4mil" ) );
553 }
554 else if( rulekind == wxT( "PlaneClearance" ) )
555 {
556 kind = ALTIUM_RULE_KIND::PLANE_CLEARANCE;
557 planeclearanceClearance = ALTIUM_PARSER::ReadKicadUnit( props, wxT( "CLEARANCE" ), wxT( "10mil" ) );
558 }
559 else if( rulekind == wxT( "PolygonConnect" ) )
560 {
561 kind = ALTIUM_RULE_KIND::POLYGON_CONNECT;
562 polygonconnectAirgapwidth = ALTIUM_PARSER::ReadKicadUnit( props, wxT( "AIRGAPWIDTH" ), wxT( "10mil" ) );
563 polygonconnectReliefconductorwidth = ALTIUM_PARSER::ReadKicadUnit( props, wxT( "RELIEFCONDUCTORWIDTH" ), wxT( "10mil" ) );
564 polygonconnectReliefentries = ALTIUM_PARSER::ReadInt( props, wxT( "RELIEFENTRIES" ), 4 );
565
566 wxString style = ALTIUM_PARSER::ReadString( props, wxT( "CONNECTSTYLE" ), wxT( "" ) );
567
568 if( style == wxT( "Direct" ) ) polygonconnectStyle = ALTIUM_CONNECT_STYLE::DIRECT;
569 else if( style == wxT( "Relief" ) ) polygonconnectStyle = ALTIUM_CONNECT_STYLE::RELIEF;
570 else if( style == wxT( "NoConnect" ) ) polygonconnectStyle = ALTIUM_CONNECT_STYLE::NONE;
571 else polygonconnectStyle = ALTIUM_CONNECT_STYLE::UNKNOWN;
572 }
573 else
574 {
575 kind = ALTIUM_RULE_KIND::UNKNOWN;
576 }
577
578 if( aReader.HasParsingError() )
579 THROW_IO_ERROR( wxT( "Rules6 stream was not parsed correctly" ) );
580}
581
583{
584 ALTIUM_RECORD recordtype = static_cast<ALTIUM_RECORD>( aReader.Read<uint8_t>() );
585 if( recordtype != ALTIUM_RECORD::ARC )
586 {
587 THROW_IO_ERROR( wxT( "Arcs6 stream has invalid recordtype" ) );
588 }
589
590 // Subrecord 1
592
593 layer = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
594
595 uint8_t flags1 = aReader.Read<uint8_t>();
596 is_locked = ( flags1 & 0x04 ) == 0;
597 is_polygonoutline = ( flags1 & 0x02 ) != 0;
598
599 uint8_t flags2 = aReader.Read<uint8_t>();
600 is_keepout = flags2 == 2;
601
602 net = aReader.Read<uint16_t>();
603 subpolyindex = aReader.Read<uint16_t>();
604 component = aReader.Read<uint16_t>();
605 aReader.Skip( 4 );
606 center = aReader.ReadVector2IPos();
607 radius = aReader.ReadKicadUnit();
608 startangle = aReader.Read<double>();
609 endangle = aReader.Read<double>();
610 width = aReader.ReadKicadUnit();
611
612 if( aReader.GetRemainingSubrecordBytes() >= 12 )
613 {
614 aReader.Skip( 11 );
615 keepoutrestrictions = aReader.Read<uint8_t>();
616 }
617 else
618 {
619 keepoutrestrictions = is_keepout ? 0x1F : 0;
620 }
621
622 aReader.SkipSubrecord();
623
624 if( aReader.HasParsingError() )
625 {
626 THROW_IO_ERROR( wxT( "Arcs6 stream was not parsed correctly" ) );
627 }
628}
629
631{
632 ALTIUM_RECORD recordtype = static_cast<ALTIUM_RECORD>( aReader.Read<uint8_t>() );
633
634 if( recordtype != ALTIUM_RECORD::MODEL )
635 THROW_IO_ERROR( wxT( "ComponentsBodies6 stream has invalid recordtype" ) );
636
638
639 aReader.Skip( 7 );
640 component = aReader.Read<uint16_t>();
641 aReader.Skip( 9 );
642
643 std::map<wxString, wxString> properties = aReader.ReadProperties();
644
645 if( properties.empty() )
646 THROW_IO_ERROR( wxT( "ComponentsBodies6 stream has no properties" ) );
647
648 modelName = ALTIUM_PARSER::ReadString( properties, wxT( "MODEL.NAME" ), wxT( "" ) );
649 modelId = ALTIUM_PARSER::ReadString( properties, wxT( "MODELID" ), wxT( "" ) );
650 modelIsEmbedded = ALTIUM_PARSER::ReadBool( properties, wxT( "MODEL.EMBED" ), false );
651
652 modelPosition.x = ALTIUM_PARSER::ReadKicadUnit( properties, wxT( "MODEL.2D.X" ), wxT( "0mil" ) );
653 modelPosition.y = -ALTIUM_PARSER::ReadKicadUnit( properties, wxT( "MODEL.2D.Y" ), wxT( "0mil" ) );
654 modelPosition.z = ALTIUM_PARSER::ReadKicadUnit( properties, wxT( "MODEL.3D.DZ" ), wxT( "0mil" ) );
655
656 modelRotation.x = ALTIUM_PARSER::ReadDouble( properties, wxT( "MODEL.3D.ROTX" ), 0. );
657 modelRotation.y = ALTIUM_PARSER::ReadDouble( properties, wxT( "MODEL.3D.ROTY" ), 0. );
658 modelRotation.z = ALTIUM_PARSER::ReadDouble( properties, wxT( "MODEL.3D.ROTZ" ), 0. );
659
660 rotation = ALTIUM_PARSER::ReadDouble( properties, wxT( "MODEL.2D.ROTATION" ), 0. );
661
662 bodyOpacity = ALTIUM_PARSER::ReadDouble( properties, wxT( "BODYOPACITY3D" ), 1. );
663
664 aReader.SkipSubrecord();
665
666 if( aReader.HasParsingError() )
667 THROW_IO_ERROR( wxT( "Components6 stream was not parsed correctly" ) );
668}
669
671{
672 ALTIUM_RECORD recordtype = static_cast<ALTIUM_RECORD>( aReader.Read<uint8_t>() );
673
674 if( recordtype != ALTIUM_RECORD::PAD )
675 THROW_IO_ERROR( wxT( "Pads6 stream has invalid recordtype" ) );
676
677 // Subrecord 1
678 size_t subrecord1 = aReader.ReadAndSetSubrecordLength();
679
680 if( subrecord1 == 0 )
681 THROW_IO_ERROR( wxT( "Pads6 stream has no subrecord1 data" ) );
682
683 name = aReader.ReadWxString();
684
685 if( aReader.GetRemainingSubrecordBytes() != 0 )
686 THROW_IO_ERROR( wxT( "Pads6 stream has invalid subrecord1 length" ) );
687
688 aReader.SkipSubrecord();
689
690 // Subrecord 2
692 aReader.SkipSubrecord();
693
694 // Subrecord 3
696 aReader.SkipSubrecord();
697
698 // Subrecord 4
700 aReader.SkipSubrecord();
701
702 // Subrecord 5
703 size_t subrecord5 = aReader.ReadAndSetSubrecordLength();
704
705 if( subrecord5 < 114 )
706 THROW_IO_ERROR( wxT( "Pads6 stream subrecord has length < 114, which is unexpected" ) );
707
708 layer = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
709 tolayer = ALTIUM_LAYER::UNKNOWN;
710 fromlayer = ALTIUM_LAYER::UNKNOWN;
711
712 uint8_t flags1 = aReader.Read<uint8_t>();
713 is_test_fab_top = ( flags1 & 0x80 ) != 0;
714 is_tent_bottom = ( flags1 & 0x40 ) != 0;
715 is_tent_top = ( flags1 & 0x20 ) != 0;
716 is_locked = ( flags1 & 0x04 ) == 0;
717
718 uint8_t flags2 = aReader.Read<uint8_t>();
719 is_test_fab_bottom = ( flags2 & 0x01 ) != 0;
720
721 net = aReader.Read<uint16_t>();
722 aReader.Skip( 2 );
723 component = aReader.Read<uint16_t>();
724 aReader.Skip( 4 );
725
726 position = aReader.ReadVector2IPos();
727 topsize = aReader.ReadVector2ISize();
728 midsize = aReader.ReadVector2ISize();
729 botsize = aReader.ReadVector2ISize();
730 holesize = aReader.ReadKicadUnit();
731
732 topshape = static_cast<ALTIUM_PAD_SHAPE>( aReader.Read<uint8_t>() );
733 midshape = static_cast<ALTIUM_PAD_SHAPE>( aReader.Read<uint8_t>() );
734 botshape = static_cast<ALTIUM_PAD_SHAPE>( aReader.Read<uint8_t>() );
735
736 direction = aReader.Read<double>();
737 plated = aReader.Read<uint8_t>() != 0;
738 aReader.Skip( 1 );
739 padmode = static_cast<ALTIUM_PAD_MODE>( aReader.Read<uint8_t>() );
740 aReader.Skip( 23 );
743 aReader.Skip( 7 );
744 pastemaskexpansionmode = static_cast<ALTIUM_MODE>( aReader.Read<uint8_t>() );
745 soldermaskexpansionmode = static_cast<ALTIUM_MODE>( aReader.Read<uint8_t>() );
746 aReader.Skip( 3 );
747 holerotation = aReader.Read<double>();
748
749 if( subrecord5 >= 120 )
750 {
751 tolayer = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
752 aReader.Skip( 2 );
753 fromlayer = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
754 //aReader.skip( 2 );
755 }
756 else if( subrecord5 == 171 )
757 {
758 }
759
760 aReader.SkipSubrecord();
761
762 // Subrecord 6
763 size_t subrecord6 = aReader.ReadAndSetSubrecordLength();
764 // Known lengths: 596, 628, 651
765 // 596 is the number of bytes read in this code-block
766 if( subrecord6 >= 596 )
767 { // TODO: detect type from something else than the size?
768 sizeAndShape = std::make_unique<APAD6_SIZE_AND_SHAPE>();
769
770 for( wxSize& size : sizeAndShape->inner_size )
771 size.x = aReader.ReadKicadUnitX();
772
773 for( wxSize& size : sizeAndShape->inner_size )
774 size.y = aReader.ReadKicadUnitY();
775
776 for( ALTIUM_PAD_SHAPE& shape : sizeAndShape->inner_shape )
777 shape = static_cast<ALTIUM_PAD_SHAPE>( aReader.Read<uint8_t>() );
778
779 aReader.Skip( 1 );
780
781 sizeAndShape->holeshape = static_cast<ALTIUM_PAD_HOLE_SHAPE>( aReader.Read<uint8_t>() );
782 sizeAndShape->slotsize = aReader.ReadKicadUnit();
783 sizeAndShape->slotrotation = aReader.Read<double>();
784
785 for( VECTOR2I& pt : sizeAndShape->holeoffset )
786 pt.x = aReader.ReadKicadUnitX();
787
788 for( VECTOR2I& pt : sizeAndShape->holeoffset )
789 pt.y = aReader.ReadKicadUnitY();
790
791 aReader.Skip( 1 );
792
793 for( ALTIUM_PAD_SHAPE_ALT& shape : sizeAndShape->alt_shape )
794 shape = static_cast<ALTIUM_PAD_SHAPE_ALT>( aReader.Read<uint8_t>() );
795
796 for( uint8_t& radius : sizeAndShape->cornerradius )
797 radius = aReader.Read<uint8_t>();
798 }
799 else if( subrecord6 != 0 )
800 {
801 wxLogError( _( "Pads6 stream has unexpected length for subrecord 6: %d." ), subrecord6 );
802 }
803
804 aReader.SkipSubrecord();
805
806 if( aReader.HasParsingError() )
807 THROW_IO_ERROR( wxT( "Pads6 stream was not parsed correctly" ) );
808}
809
811{
812 ALTIUM_RECORD recordtype = static_cast<ALTIUM_RECORD>( aReader.Read<uint8_t>() );
813
814 if( recordtype != ALTIUM_RECORD::VIA )
815 THROW_IO_ERROR( wxT( "Vias6 stream has invalid recordtype" ) );
816
817 // Subrecord 1
818 size_t subrecord1 = aReader.ReadAndSetSubrecordLength();
819
820 aReader.Skip( 1 );
821
822 uint8_t flags1 = aReader.Read<uint8_t>();
823 is_test_fab_top = ( flags1 & 0x80 ) != 0;
824 is_tent_bottom = ( flags1 & 0x40 ) != 0;
825 is_tent_top = ( flags1 & 0x20 ) != 0;
826 is_locked = ( flags1 & 0x04 ) == 0;
827
828 uint8_t flags2 = aReader.Read<uint8_t>();
829 is_test_fab_bottom = ( flags2 & 0x01 ) != 0;
830
831 net = aReader.Read<uint16_t>();
832 aReader.Skip( 8 );
833 position = aReader.ReadVector2IPos();
834 diameter = aReader.ReadKicadUnit();
835 holesize = aReader.ReadKicadUnit();
836
837 layer_start = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
838 layer_end = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
839
840 if( subrecord1 <= 74 )
841 {
842 viamode = ALTIUM_PAD_MODE::SIMPLE;
843 }
844 else
845 {
846 aReader.Skip( 43 );
847 viamode = static_cast<ALTIUM_PAD_MODE>( aReader.Read<uint8_t>() );
848 }
849
850 aReader.SkipSubrecord();
851
852 if( aReader.HasParsingError() )
853 THROW_IO_ERROR( wxT( "Vias6 stream was not parsed correctly" ) );
854}
855
857{
858 ALTIUM_RECORD recordtype = static_cast<ALTIUM_RECORD>( aReader.Read<uint8_t>() );
859
860 if( recordtype != ALTIUM_RECORD::TRACK )
861 THROW_IO_ERROR( wxT( "Tracks6 stream has invalid recordtype" ) );
862
863 // Subrecord 1
865
866 layer = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
867
868 uint8_t flags1 = aReader.Read<uint8_t>();
869 is_locked = ( flags1 & 0x04 ) == 0;
870 is_polygonoutline = ( flags1 & 0x02 ) != 0;
871
872 uint8_t flags2 = aReader.Read<uint8_t>();
873 is_keepout = flags2 == 2;
874
875 net = aReader.Read<uint16_t>();
876 subpolyindex = aReader.Read<uint16_t>();
877 component = aReader.Read<uint16_t>();
878 aReader.Skip( 4 );
879 start = aReader.ReadVector2IPos();
880 end = aReader.ReadVector2IPos();
881 width = aReader.ReadKicadUnit();
882
883 if( aReader.GetRemainingSubrecordBytes() >= 13 )
884 {
885 aReader.Skip( 12 );
886 keepoutrestrictions = aReader.Read<uint8_t>();
887 }
888 else
889 {
890 keepoutrestrictions = is_keepout ? 0x1F : 0;
891 }
892
893 aReader.SkipSubrecord();
894
895 if( aReader.HasParsingError() )
896 THROW_IO_ERROR( wxT( "Tracks6 stream was not parsed correctly" ) );
897}
898
899ATEXT6::ATEXT6( ALTIUM_PARSER& aReader, std::map<uint32_t, wxString>& aStringTable )
900{
901 ALTIUM_RECORD recordtype = static_cast<ALTIUM_RECORD>( aReader.Read<uint8_t>() );
902
903 if( recordtype != ALTIUM_RECORD::TEXT )
904 THROW_IO_ERROR( wxT( "Texts6 stream has invalid recordtype" ) );
905
906 // Subrecord 1 - Properties
907 size_t subrecord1 = aReader.ReadAndSetSubrecordLength();
908
909 layer = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
910 aReader.Skip( 6 );
911 component = aReader.Read<uint16_t>();
912 aReader.Skip( 4 );
913 position = aReader.ReadVector2IPos();
914 height = aReader.ReadKicadUnit();
915 aReader.Skip( 2 );
916 rotation = aReader.Read<double>();
917 isMirrored = aReader.Read<uint8_t>() != 0;
918 strokewidth = aReader.ReadKicadUnit();
919 isComment = aReader.Read<uint8_t>() != 0;
920 isDesignator = aReader.Read<uint8_t>() != 0;
921 aReader.Skip( 2 );
922 isBold = aReader.Read<uint8_t>() != 0;
923 isItalic = aReader.Read<uint8_t>() != 0;
924
925 char fontData[64] = { 0 };
926 aReader.ReadBytes( fontData, sizeof( fontData ) );
927 fontname = wxString( fontData, wxMBConvUTF16LE(), sizeof( fontData ) ).BeforeFirst( '\0' );
928
929 isInverted = aReader.Read<uint8_t>() != 0;
930 aReader.Skip( 4 );
931 uint32_t stringIndex = aReader.Read<uint32_t>();
932 aReader.Skip( 13 );
933 textposition = static_cast<ALTIUM_TEXT_POSITION>( aReader.Read<uint8_t>() );
938 if( subrecord1 <= 230 )
939 textposition = ALTIUM_TEXT_POSITION::LEFT_BOTTOM;
940
941 aReader.Skip( 27 );
942 fonttype = static_cast<ALTIUM_TEXT_TYPE>( aReader.Read<uint8_t>() );
943
944 aReader.SkipSubrecord();
945
946 // Subrecord 2 - Legacy 8bit string, max 255 chars, unknown codepage
948
949 auto entry = aStringTable.find( stringIndex );
950
951 if( entry != aStringTable.end() )
952 text = entry->second;
953 else
954 text = aReader.ReadWxString();
955
956 // Normalize Windows line endings
957 text.Replace( wxT( "\r\n" ), wxT( "\n" ) );
958
959 aReader.SkipSubrecord();
960
961 if( aReader.HasParsingError() )
962 THROW_IO_ERROR( wxT( "Texts6 stream was not parsed correctly" ) );
963}
964
966{
967 ALTIUM_RECORD recordtype = static_cast<ALTIUM_RECORD>( aReader.Read<uint8_t>() );
968
969 if( recordtype != ALTIUM_RECORD::FILL )
970 THROW_IO_ERROR( wxT( "Fills6 stream has invalid recordtype" ) );
971
972 // Subrecord 1
974
975 layer = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
976
977 uint8_t flags1 = aReader.Read<uint8_t>();
978 is_locked = ( flags1 & 0x04 ) == 0;
979
980 uint8_t flags2 = aReader.Read<uint8_t>();
981 is_keepout = flags2 == 2;
982
983 net = aReader.Read<uint16_t>();
984 aReader.Skip( 2 );
985 component = aReader.Read<uint16_t>();
986 aReader.Skip( 4 );
987 pos1 = aReader.ReadVector2IPos();
988 pos2 = aReader.ReadVector2IPos();
989 rotation = aReader.Read<double>();
990
991 if( aReader.GetRemainingSubrecordBytes() >= 10 )
992 {
993 aReader.Skip( 9 );
994 keepoutrestrictions = aReader.Read<uint8_t>();
995 }
996 else
997 {
998 keepoutrestrictions = is_keepout ? 0x1F : 0;
999 }
1000
1001 aReader.SkipSubrecord();
1002
1003 if( aReader.HasParsingError() )
1004 THROW_IO_ERROR( wxT( "Fills6 stream was not parsed correctly" ) );
1005}
1006
1007AREGION6::AREGION6( ALTIUM_PARSER& aReader, bool aExtendedVertices )
1008{
1009 ALTIUM_RECORD recordtype = static_cast<ALTIUM_RECORD>( aReader.Read<uint8_t>() );
1010
1011 if( recordtype != ALTIUM_RECORD::REGION )
1012 THROW_IO_ERROR( wxT( "Regions6 stream has invalid recordtype" ) );
1013
1014 // Subrecord 1
1015 aReader.ReadAndSetSubrecordLength();
1016
1017 layer = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
1018
1019 uint8_t flags1 = aReader.Read<uint8_t>();
1020 is_locked = ( flags1 & 0x04 ) == 0;
1021
1022 uint8_t flags2 = aReader.Read<uint8_t>();
1023 is_keepout = flags2 == 2;
1024
1025 net = aReader.Read<uint16_t>();
1026 subpolyindex = aReader.Read<uint16_t>();
1027 component = aReader.Read<uint16_t>();
1028 aReader.Skip( 5 );
1029 holecount = aReader.Read<uint16_t>();
1030 aReader.Skip( 2 );
1031
1032 std::map<wxString, wxString> properties = aReader.ReadProperties();
1033
1034 if( properties.empty() )
1035 THROW_IO_ERROR( wxT( "Regions6 stream has empty properties" ) );
1036
1037 int pkind = ALTIUM_PARSER::ReadInt( properties, wxT( "KIND" ), 0 );
1038 bool is_cutout = ALTIUM_PARSER::ReadBool( properties, wxT( "ISBOARDCUTOUT" ), false );
1039
1040 is_shapebased = ALTIUM_PARSER::ReadBool( properties, wxT( "ISSHAPEBASED" ), false );
1041 keepoutrestrictions = static_cast<uint8_t>(
1042 ALTIUM_PARSER::ReadInt( properties, wxT( "KEEPOUTRESTRIC" ), 0x1F ) );
1043
1044 // TODO: this can differ from the other subpolyindex?!
1045 //subpolyindex = static_cast<uint16_t>(
1046 // ALTIUM_PARSER::ReadInt( properties, "SUBPOLYINDEX", ALTIUM_POLYGON_NONE ) );
1047
1048 switch( pkind )
1049 {
1050 case 0:
1051 if( is_cutout )
1052 {
1053 kind = ALTIUM_REGION_KIND::BOARD_CUTOUT;
1054 }
1055 else
1056 {
1057 kind = ALTIUM_REGION_KIND::COPPER;
1058 }
1059 break;
1060 case 1:
1061 kind = ALTIUM_REGION_KIND::POLYGON_CUTOUT;
1062 break;
1063 case 2:
1064 kind = ALTIUM_REGION_KIND::DASHED_OUTLINE;
1065 break;
1066 case 3:
1067 kind = ALTIUM_REGION_KIND::UNKNOWN_3; // TODO: what kind is this?
1068 break;
1069 case 4:
1070 kind = ALTIUM_REGION_KIND::CAVITY_DEFINITION;
1071 break;
1072 default:
1073 kind = ALTIUM_REGION_KIND::UNKNOWN;
1074 break;
1075 }
1076
1077 uint32_t num_outline_vertices = aReader.Read<uint32_t>();
1078
1079 if( aExtendedVertices )
1080 num_outline_vertices++; // Has a closing vertex
1081
1082 for( uint32_t i = 0; i < num_outline_vertices; i++ )
1083 {
1084 if( aExtendedVertices )
1085 {
1086 bool isRound = aReader.Read<uint8_t>() != 0;
1087 VECTOR2I position = aReader.ReadVector2IPos();
1088 VECTOR2I center = aReader.ReadVector2IPos();
1089 int32_t radius = aReader.ReadKicadUnit();
1090 double angle1 = aReader.Read<double>();
1091 double angle2 = aReader.Read<double>();
1092 outline.emplace_back( isRound, radius, angle1, angle2, position, center );
1093 }
1094 else
1095 {
1096 // For some regions the coordinates are stored as double and not as int32_t
1097 int32_t x = ALTIUM_PARSER::ConvertToKicadUnit( aReader.Read<double>() );
1098 int32_t y = ALTIUM_PARSER::ConvertToKicadUnit( -aReader.Read<double>() );
1099 outline.emplace_back( VECTOR2I( x, y ) );
1100 }
1101 }
1102
1103 holes.resize( holecount );
1104 for( uint16_t k = 0; k < holecount; k++ )
1105 {
1106 uint32_t num_hole_vertices = aReader.Read<uint32_t>();
1107 holes.at( k ).reserve( num_hole_vertices );
1108
1109 for( uint32_t i = 0; i < num_hole_vertices; i++ )
1110 {
1111 int32_t x = ALTIUM_PARSER::ConvertToKicadUnit( aReader.Read<double>() );
1112 int32_t y = ALTIUM_PARSER::ConvertToKicadUnit( -aReader.Read<double>() );
1113 holes.at( k ).emplace_back( VECTOR2I( x, y ) );
1114 }
1115 }
1116
1117 aReader.SkipSubrecord();
1118
1119 if( aReader.HasParsingError() )
1120 THROW_IO_ERROR( wxT( "Regions6 stream was not parsed correctly" ) );
1121}
void altium_parse_polygons(std::map< wxString, wxString > &aProps, std::vector< ALTIUM_VERTICE > &aVertices)
ALTIUM_LAYER altium_layer_from_name(const wxString &aName)
static AEXTENDED_PRIMITIVE_INFORMATION_TYPE ReadAltiumExtendedPrimitiveInformationTypeFromProperties(const std::map< wxString, wxString > &aProps, wxString aKey)
static ALTIUM_MODE ReadAltiumModeFromProperties(const std::map< wxString, wxString > &aProps, wxString aKey)
static ALTIUM_RECORD ReadAltiumRecordFromProperties(const std::map< wxString, wxString > &aProps, wxString aKey)
ALTIUM_PAD_SHAPE_ALT
ALTIUM_TEXT_POSITION
ALTIUM_PAD_MODE
ALTIUM_TEXT_TYPE
ALTIUM_PAD_SHAPE
ALTIUM_DIMENSION_KIND
ALTIUM_PAD_HOLE_SHAPE
const uint16_t ALTIUM_NET_UNCONNECTED
ALTIUM_CLASS_KIND
ALTIUM_MODE
ALTIUM_LAYER
AEXTENDED_PRIMITIVE_INFORMATION_TYPE
ALTIUM_RECORD
wxString ReadWxString()
static int ReadInt(const std::map< wxString, wxString > &aProps, const wxString &aKey, int aDefault)
int32_t ReadKicadUnitX()
bool HasParsingError()
size_t GetRemainingSubrecordBytes() const
static wxString ReadString(const std::map< wxString, wxString > &aProps, const wxString &aKey, const wxString &aDefault)
std::map< wxString, wxString > ReadProperties(std::function< std::map< wxString, wxString >(const std::string &)> handleBinaryData=[](const std::string &) { return std::map< wxString, wxString >();})
size_t ReadAndSetSubrecordLength()
int32_t ReadKicadUnitY()
int ReadBytes(char *aOut, size_t aSize)
static double ReadDouble(const std::map< wxString, wxString > &aProps, const wxString &aKey, double aDefault)
VECTOR2I ReadVector2ISize()
static int32_t ConvertToKicadUnit(const double aValue)
int32_t ReadKicadUnit()
static bool ReadBool(const std::map< wxString, wxString > &aProps, const wxString &aKey, bool aDefault)
VECTOR2I ReadVector2IPos()
void Skip(size_t aLength)
static wxString ReadUnicodeString(const std::map< wxString, wxString > &aProps, const wxString &aKey, const wxString &aDefault)
void SkipSubrecord()
T y
Definition: vector3.h:63
T z
Definition: vector3.h:64
T x
Definition: vector3.h:62
#define _(s)
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38
double startangle
uint16_t component
bool is_keepout
uint32_t width
AARC6(ALTIUM_PARSER &aReader)
ALTIUM_LAYER layer
uint8_t keepoutrestrictions
VECTOR2I center
uint32_t radius
uint16_t net
bool is_locked
bool is_polygonoutline
double endangle
uint16_t subpolyindex
ABOARD6(ALTIUM_PARSER &aReader)
VECTOR2I sheetpos
std::set< wxString > layerNames
wxSize sheetsize
std::vector< ABOARD6_LAYER_STACKUP > stackup
std::vector< ALTIUM_VERTICE > board_vertices
wxString uniqueid
std::vector< wxString > names
ALTIUM_CLASS_KIND kind
wxString name
ACLASS6(ALTIUM_PARSER &aReader)
ALTIUM_TEXT_POSITION commentautoposition
ALTIUM_TEXT_POSITION nameautoposition
ACOMPONENT6(ALTIUM_PARSER &aReader)
wxString sourcefootprintlibrary
ALTIUM_LAYER layer
wxString sourcelibreference
wxString sourcedesignator
wxString sourcecomponentlibrary
ACOMPONENTBODY6(ALTIUM_PARSER &aReader)
int32_t textprecision
ALTIUM_UNIT textunit
wxString textsuffix
ADIMENSION6(ALTIUM_PARSER &aReader)
uint32_t textlinewidth
wxString textformat
ALTIUM_LAYER layer
std::vector< VECTOR2I > textPoint
wxString textprefix
uint32_t linewidth
ALTIUM_DIMENSION_KIND kind
uint32_t textheight
std::vector< VECTOR2I > referencePoint
AEXTENDED_PRIMITIVE_INFORMATION_TYPE type
AEXTENDED_PRIMITIVE_INFORMATION(ALTIUM_PARSER &aReader)
VECTOR2I pos2
ALTIUM_LAYER layer
uint16_t net
VECTOR2I pos1
double rotation
uint8_t keepoutrestrictions
uint16_t component
AFILL6(ALTIUM_PARSER &aReader)
wxString name
VECTOR3D rotation
AMODEL(ALTIUM_PARSER &aReader)
ANET6(ALTIUM_PARSER &aReader)
wxString name
double holerotation
int32_t soldermaskexpansionmanual
uint16_t net
ALTIUM_LAYER layer
std::unique_ptr< APAD6_SIZE_AND_SHAPE > sizeAndShape
ALTIUM_LAYER tolayer
ALTIUM_PAD_SHAPE topshape
ALTIUM_PAD_MODE padmode
ALTIUM_MODE pastemaskexpansionmode
uint32_t holesize
double direction
ALTIUM_MODE soldermaskexpansionmode
wxString name
bool is_test_fab_bottom
bool is_tent_bottom
VECTOR2I botsize
ALTIUM_PAD_SHAPE botshape
uint16_t component
VECTOR2I midsize
ALTIUM_PAD_SHAPE midshape
int32_t pastemaskexpansionmanual
bool is_tent_top
APAD6(ALTIUM_PARSER &aReader)
ALTIUM_LAYER fromlayer
VECTOR2I position
bool is_locked
VECTOR2I topsize
bool is_test_fab_top
APOLYGON6(ALTIUM_PARSER &aReader)
int32_t minprimlength
std::vector< ALTIUM_VERTICE > vertices
ALTIUM_POLYGON_HATCHSTYLE hatchstyle
int32_t pourindex
int32_t trackwidth
ALTIUM_LAYER layer
int32_t gridsize
uint8_t keepoutrestrictions
ALTIUM_LAYER layer
AREGION6(ALTIUM_PARSER &aReader, bool aExtendedVertices)
uint16_t holecount
std::vector< ALTIUM_VERTICE > outline
uint16_t subpolyindex
std::vector< std::vector< ALTIUM_VERTICE > > holes
uint16_t component
uint16_t net
ALTIUM_REGION_KIND kind
ALTIUM_RULE_KIND kind
ALTIUM_CONNECT_STYLE polygonconnectStyle
wxString scope1expr
wxString name
int planeclearanceClearance
int32_t polygonconnectReliefconductorwidth
int pastemaskExpansion
wxString scope2expr
ARULE6(ALTIUM_PARSER &aReader)
int soldermaskExpansion
int32_t polygonconnectAirgapwidth
int polygonconnectReliefentries
ALTIUM_TEXT_POSITION textposition
uint16_t component
wxString text
double rotation
ATEXT6(ALTIUM_PARSER &aReader, std::map< uint32_t, wxString > &aStringTable)
uint32_t height
wxString fontname
ALTIUM_LAYER layer
VECTOR2I position
ALTIUM_TEXT_TYPE fonttype
bool isDesignator
uint32_t strokewidth
VECTOR2I end
uint32_t width
bool is_polygonoutline
uint16_t net
uint16_t subpolyindex
uint8_t keepoutrestrictions
ATRACK6(ALTIUM_PARSER &aReader)
VECTOR2I start
ALTIUM_LAYER layer
uint16_t component
uint32_t diameter
uint16_t net
VECTOR2I position
bool is_locked
bool is_tent_top
bool is_test_fab_top
bool is_tent_bottom
bool is_test_fab_bottom
AVIA6(ALTIUM_PARSER &aReader)
ALTIUM_PAD_MODE viamode
ALTIUM_LAYER layer_start
ALTIUM_LAYER layer_end
uint32_t holesize
VECTOR2< int > VECTOR2I
Definition: vector2d.h:588