KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcb_easyedapro_parser.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 Alex Shvartzkop <[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
27
28#include <memory>
29
30#include <nlohmann/json.hpp>
32#include <core/map_helpers.h>
33#include <string_utils.h>
34
35#include <wx/wfstream.h>
36#include <wx/stdstream.h>
37#include <wx/log.h>
38#include <glm/glm.hpp>
39
40#include <progress_reporter.h>
41#include <footprint.h>
42#include <board.h>
44#include <bezier_curves.h>
45#include <pcb_group.h>
46#include <pcb_track.h>
47#include <pcb_shape.h>
48#include <pcb_text.h>
49#include <font/font.h>
50#include <geometry/shape_arc.h>
53#include <geometry/shape_rect.h>
55#include <zone.h>
56#include <pad.h>
58#include <project.h>
59#include <fix_board_shape.h>
60
61
62static const wxString QUERY_MODEL_UUID_KEY = wxS( "JLC_3DModel_Q" );
63static const wxString MODEL_SIZE_KEY = wxS( "JLC_3D_Size" );
64
65static const int SHAPE_JOIN_DISTANCE = pcbIUScale.mmToIU( 1.5 );
66
67
68double PCB_EASYEDAPRO_PARSER::Convert( wxString aValue )
69{
70 double value = 0;
71
72 if( !aValue.ToCDouble( &value ) )
73 THROW_IO_ERROR( wxString::Format( _( "Failed to parse value: '%s'" ), aValue ) );
74
75 return value;
76}
77
78
80{
81 m_board = aBoard;
82}
83
84
86{
87}
88
89
91{
92 switch( aLayer )
93 {
94 case 1: return F_Cu;
95 case 2: return B_Cu;
96 case 3: return F_SilkS;
97 case 4: return B_SilkS;
98 case 5: return F_Mask;
99 case 6: return B_Mask;
100 case 7: return F_Paste;
101 case 8: return B_Paste;
102 case 9: return F_Fab;
103 case 10: return B_Fab;
104 case 11: return Edge_Cuts;
105 case 12: return Edge_Cuts; // Multi
106 case 13: return Dwgs_User;
107 case 14: return Eco2_User;
108
109 case 15: return In1_Cu;
110 case 16: return In2_Cu;
111 case 17: return In3_Cu;
112 case 18: return In4_Cu;
113 case 19: return In5_Cu;
114 case 20: return In6_Cu;
115 case 21: return In7_Cu;
116 case 22: return In8_Cu;
117 case 23: return In9_Cu;
118 case 24: return In10_Cu;
119 case 25: return In11_Cu;
120 case 26: return In12_Cu;
121 case 27: return In13_Cu;
122 case 28: return In14_Cu;
123 case 29: return In15_Cu;
124 case 30: return In16_Cu;
125 case 31: return In17_Cu;
126 case 32: return In18_Cu;
127 case 33: return In19_Cu;
128 case 34: return In20_Cu;
129 case 35: return In21_Cu;
130 case 36: return In22_Cu;
131 case 37: return In23_Cu;
132 case 38: return In24_Cu;
133 case 39: return In25_Cu;
134 case 40: return In26_Cu;
135 case 41: return In27_Cu;
136 case 42: return In28_Cu;
137 case 43: return In29_Cu;
138 case 44: return In30_Cu;
139
140 case 48: return User_2; // Component shape layer
141 case 49: return User_3; // Component marking
142
143 case 53: return User_4; // 3D shell outline
144 case 54: return User_5; // 3D shell top
145 case 55: return User_6; // 3D shell bot
146 case 56: return User_7; // Drill drawing
147
148 default: break;
149 }
150
151 return User_1;
152}
153
154
155static void AlignText( EDA_TEXT* text, int align )
156{
157 switch( align )
158 {
159 case 1:
160 text->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
161 text->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
162 break;
163 case 2:
164 text->SetVertJustify( GR_TEXT_V_ALIGN_CENTER );
165 text->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
166 break;
167 case 3:
168 text->SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM );
169 text->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
170 break;
171
172 case 4:
173 text->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
174 text->SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
175 break;
176 case 5:
177 text->SetVertJustify( GR_TEXT_V_ALIGN_CENTER );
178 text->SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
179 break;
180 case 6:
181 text->SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM );
182 text->SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
183 break;
184
185 case 7:
186 text->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
187 text->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
188 break;
189 case 8:
190 text->SetVertJustify( GR_TEXT_V_ALIGN_CENTER );
191 text->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
192 break;
193 case 9:
194 text->SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM );
195 text->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
196 break;
197 }
198}
199
200
201void PCB_EASYEDAPRO_PARSER::fillFootprintModelInfo( FOOTPRINT* footprint, const wxString& modelUuid,
202 const wxString& modelTitle,
203 const wxString& modelTransform ) const
204{
205 // TODO: make this path configurable?
206 const wxString easyedaModelDir = wxS( "EASYEDA_MODELS" );
207 const wxString kicadModelPrefix = wxS( "${KIPRJMOD}/" ) + easyedaModelDir + wxS( "/" );
208
209 VECTOR3D kmodelOffset;
210 VECTOR3D kmodelRotation;
211
212 if( !modelUuid.IsEmpty() && !footprint->GetFieldByName( QUERY_MODEL_UUID_KEY ) )
213 {
214 PCB_FIELD field( footprint, footprint->GetFieldCount(), QUERY_MODEL_UUID_KEY );
215 field.SetLayer( Cmts_User );
216 field.SetVisible( false );
217 field.SetText( modelUuid );
218 footprint->AddField( field );
219 }
220
221 if( !modelTransform.IsEmpty() && !footprint->GetFieldByName( MODEL_SIZE_KEY ) )
222 {
223 wxArrayString arr = wxSplit( modelTransform, ',', '\0' );
224
225 double fitXmm = pcbIUScale.IUTomm( ScaleSize( Convert( arr[0] ) ) );
226 double fitYmm = pcbIUScale.IUTomm( ScaleSize( Convert( arr[1] ) ) );
227
228 if( fitXmm > 0.0 && fitYmm > 0.0 )
229 {
230 PCB_FIELD field( footprint, footprint->GetFieldCount(), MODEL_SIZE_KEY );
231 field.SetLayer( Cmts_User );
232 field.SetVisible( false );
233 field.SetText( wxString::FromCDouble( fitXmm ) + wxS( " " )
234 + wxString::FromCDouble( fitYmm ) );
235 footprint->AddField( field );
236 }
237
238 // TODO: other axes
239 kmodelRotation.z = -Convert( arr[3] );
240
241 kmodelOffset.x = pcbIUScale.IUTomm( ScaleSize( Convert( arr[6] ) ) );
242 kmodelOffset.y = pcbIUScale.IUTomm( ScaleSize( Convert( arr[7] ) ) );
243 kmodelOffset.z = pcbIUScale.IUTomm( ScaleSize( Convert( arr[8] ) ) );
244 }
245
246 if( !modelTitle.IsEmpty() && footprint->Models().empty() )
247 {
248 FP_3DMODEL model;
249 model.m_Filename = kicadModelPrefix
250 + EscapeString( modelTitle, ESCAPE_CONTEXT::CTX_FILENAME )
251 + wxS( ".step" );
252 model.m_Offset = kmodelOffset;
253 model.m_Rotation = kmodelRotation;
254 footprint->Models().push_back( model );
255 }
256}
257
258
259std::vector<std::unique_ptr<PCB_SHAPE>>
260PCB_EASYEDAPRO_PARSER::ParsePoly( BOARD_ITEM_CONTAINER* aContainer, nlohmann::json polyData,
261 bool aClosed, bool aInFill ) const
262{
263 std::vector<std::unique_ptr<PCB_SHAPE>> results;
264
265 VECTOR2D prevPt;
266 for( int i = 0; i < polyData.size(); i++ )
267 {
268 nlohmann::json val = polyData.at( i );
269
270 if( val.is_string() )
271 {
272 wxString str = val;
273 if( str == wxS( "CIRCLE" ) )
274 {
275 VECTOR2D center;
276 center.x = ( polyData.at( ++i ) );
277 center.y = ( polyData.at( ++i ) );
278 double r = ( polyData.at( ++i ) );
279
280 std::unique_ptr<PCB_SHAPE> shape =
281 std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::CIRCLE );
282
283 shape->SetCenter( ScalePos( center ) );
284 shape->SetEnd( ScalePos( center + VECTOR2D( r, 0 ) ) );
285 shape->SetFilled( aClosed );
286
287 results.emplace_back( std::move( shape ) );
288 }
289 else if( str == wxS( "R" ) )
290 {
291 VECTOR2D start, size;
292 start.x = ( polyData.at( ++i ) );
293 start.y = ( polyData.at( ++i ) );
294 size.x = ( polyData.at( ++i ) );
295 size.y = -( polyData.at( ++i ).get<double>() );
296 double angle = polyData.at( ++i );
297 double cr = ( i + 1 ) < polyData.size() ? polyData.at( ++i ).get<double>() : 0;
298
299 if( cr == 0 )
300 {
301 std::unique_ptr<PCB_SHAPE> shape =
302 std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::RECTANGLE );
303
304 shape->SetStart( ScalePos( start ) );
305 shape->SetEnd( ScalePos( start + size ) );
306 shape->SetFilled( aClosed );
307 shape->Rotate( ScalePos( start ), EDA_ANGLE( angle, DEGREES_T ) );
308
309 results.emplace_back( std::move( shape ) );
310 }
311 else
312 {
313 VECTOR2D end = start + size;
314
315 auto addSegment = [&]( VECTOR2D aStart, VECTOR2D aEnd )
316 {
317 std::unique_ptr<PCB_SHAPE> shape =
318 std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::SEGMENT );
319
320 shape->SetStart( ScalePos( aStart ) );
321 shape->SetEnd( ScalePos( aEnd ) );
322 shape->SetFilled( aClosed );
323 shape->Rotate( ScalePos( start ), EDA_ANGLE( angle, DEGREES_T ) );
324
325 results.emplace_back( std::move( shape ) );
326 };
327
328 auto addArc = [&]( VECTOR2D aStart, VECTOR2D aEnd, VECTOR2D center )
329 {
330 std::unique_ptr<PCB_SHAPE> shape =
331 std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::ARC );
332
333 shape->SetStart( ScalePos( aStart ) );
334 shape->SetEnd( ScalePos( aEnd ) );
335 shape->SetCenter( ScalePos( center ) );
336 shape->SetFilled( aClosed );
337 shape->Rotate( ScalePos( start ), EDA_ANGLE( angle, DEGREES_T ) );
338
339 results.emplace_back( std::move( shape ) );
340 };
341
342 addSegment( { start.x + cr, start.y }, { end.x - cr, start.y } );
343 addSegment( { end.x, start.y - cr }, { end.x, end.y + cr } );
344 addSegment( { start.x + cr, end.y }, { end.x - cr, end.y } );
345 addSegment( { start.x, start.y - cr }, { start.x, end.y + cr } );
346
347 addArc( { end.x - cr, start.y }, { end.x, start.y - cr },
348 { end.x - cr, start.y - cr } );
349
350 addArc( { end.x, end.y + cr }, { end.x - cr, end.y },
351 { end.x - cr, end.y + cr } );
352
353 addArc( { start.x + cr, end.y }, { start.x, end.y + cr },
354 { start.x + cr, end.y + cr } );
355
356 addArc( { start.x, start.y - cr }, { start.x + cr, start.y },
357 { start.x + cr, start.y - cr } );
358 }
359 }
360 else if( str == wxS( "ARC" ) || str == wxS( "CARC" ) )
361 {
362 VECTOR2D end;
363 double angle = polyData.at( ++i ).get<double>() / ( aInFill ? 10 : 1 );
364 end.x = ( polyData.at( ++i ) );
365 end.y = ( polyData.at( ++i ) );
366
367 std::unique_ptr<PCB_SHAPE> shape =
368 std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::ARC );
369
370 if( angle < 0 )
371 {
372 shape->SetStart( ScalePos( prevPt ) );
373 shape->SetEnd( ScalePos( end ) );
374 }
375 else
376 {
377 shape->SetStart( ScalePos( end ) );
378 shape->SetEnd( ScalePos( prevPt ) );
379 }
380
381 VECTOR2D delta = end - prevPt;
382 VECTOR2D mid = ( prevPt + delta / 2 );
383
384 double ha = angle / 2;
385 double hd = delta.EuclideanNorm() / 2;
386 double cdist = hd / tan( DEG2RAD( ha ) );
387 VECTOR2D center = mid + delta.Perpendicular().Resize( cdist );
388 shape->SetCenter( ScalePos( center ) );
389
390 shape->SetFilled( aClosed );
391
392 results.emplace_back( std::move( shape ) );
393
394 prevPt = end;
395 }
396 else if( str == wxS( "L" ) )
397 {
398 SHAPE_LINE_CHAIN chain;
399 chain.Append( ScalePos( prevPt ) );
400
401 while( i < polyData.size() - 2 && polyData.at( i + 1 ).is_number() )
402 {
403 VECTOR2D pt;
404 pt.x = ( polyData.at( ++i ) );
405 pt.y = ( polyData.at( ++i ) );
406
407 chain.Append( ScalePos( pt ) );
408
409 prevPt = pt;
410 }
411
412 if( aClosed )
413 {
414 std::unique_ptr<PCB_SHAPE> shape =
415 std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::POLY );
416
417 wxASSERT( chain.PointCount() > 2 );
418
419 if( chain.PointCount() > 2 )
420 {
421 chain.SetClosed( true );
422 shape->SetFilled( true );
423 shape->SetPolyShape( chain );
424
425 results.emplace_back( std::move( shape ) );
426 }
427 }
428 else
429 {
430 for( int s = 0; s < chain.SegmentCount(); s++ )
431 {
432 SEG seg = chain.Segment( s );
433
434 std::unique_ptr<PCB_SHAPE> shape =
435 std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::SEGMENT );
436
437 shape->SetStart( seg.A );
438 shape->SetEnd( seg.B );
439
440 results.emplace_back( std::move( shape ) );
441 }
442 }
443 }
444 }
445 else if( val.is_number() )
446 {
447 prevPt.x = ( polyData.at( i ) );
448 prevPt.y = ( polyData.at( ++i ) );
449 }
450 }
451
452 return results;
453}
454
455
457PCB_EASYEDAPRO_PARSER::ParseContour( nlohmann::json polyData, bool aInFill,
458 double aArcAccuracy ) const
459{
460 SHAPE_LINE_CHAIN result;
461 VECTOR2D prevPt;
462
463 double bezierMinSegLen = polyData.size() < 300 ? aArcAccuracy : aArcAccuracy * 10;
464
465 for( int i = 0; i < polyData.size(); i++ )
466 {
467 nlohmann::json val = polyData.at( i );
468
469 if( val.is_string() )
470 {
471 wxString str = val;
472 if( str == wxS( "CIRCLE" ) )
473 {
474 VECTOR2D center;
475 center.x = ( polyData.at( ++i ) );
476 center.y = ( polyData.at( ++i ) );
477 double r = ( polyData.at( ++i ) );
478
480 ERROR_INSIDE );
481 }
482 else if( str == wxS( "R" ) )
483 {
484 VECTOR2D start, size;
485 start.x = ( polyData.at( ++i ) );
486 start.y = ( polyData.at( ++i ) );
487 size.x = ( polyData.at( ++i ) );
488 size.y = ( polyData.at( ++i ).get<double>() );
489 double angle = polyData.at( ++i );
490 double cr = ( i + 1 ) < polyData.size() ? polyData.at( ++i ).get<double>() : 0;
491
492 SHAPE_POLY_SET poly;
493
494 VECTOR2D kstart = ScalePos( start );
495 VECTOR2D ksize = ScaleSize( size );
496 VECTOR2D kcenter = kstart + ksize / 2;
497 RotatePoint( kcenter, kstart, EDA_ANGLE( angle, DEGREES_T ) );
498
500 poly, kcenter, ksize, EDA_ANGLE( angle, DEGREES_T ), ScaleSize( cr ), 0, 0,
502
503 result.Append( poly.Outline( 0 ) );
504 }
505 else if( str == wxS( "ARC" ) || str == wxS( "CARC" ) )
506 {
507 VECTOR2D end;
508 double angle = polyData.at( ++i ).get<double>();
509
510 if( aInFill ) // In .epcb fills, the angle is 10x for some reason
511 angle /= 10;
512
513 end.x = ( polyData.at( ++i ) );
514 end.y = ( polyData.at( ++i ) );
515
516 VECTOR2D arcStart, arcEnd;
517 arcStart = prevPt;
518 arcEnd = end;
519
520 VECTOR2D delta = end - prevPt;
521 VECTOR2D mid = ( prevPt + delta / 2 );
522
523 double ha = angle / 2;
524 double hd = delta.EuclideanNorm() / 2;
525 double cdist = hd / tan( DEG2RAD( ha ) );
526 VECTOR2D center = mid + delta.Perpendicular().Resize( cdist );
527
528 SHAPE_ARC sarc;
529 sarc.ConstructFromStartEndCenter( ScalePos( arcStart ), ScalePos( arcEnd ),
530 ScalePos( center ), angle >= 0, 0 );
531
532 result.Append( sarc, aArcAccuracy );
533
534 prevPt = end;
535 }
536 else if( str == wxS( "C" ) )
537 {
538 VECTOR2D pt1;
539 pt1.x = ( polyData.at( ++i ) );
540 pt1.y = ( polyData.at( ++i ) );
541
542 VECTOR2D pt2;
543 pt2.x = ( polyData.at( ++i ) );
544 pt2.y = ( polyData.at( ++i ) );
545
546 VECTOR2D pt3;
547 pt3.x = ( polyData.at( ++i ) );
548 pt3.y = ( polyData.at( ++i ) );
549
550 std::vector<VECTOR2I> ctrlPoints = { ScalePos( prevPt ), ScalePos( pt1 ),
551 ScalePos( pt2 ), ScalePos( pt3 ) };
552 BEZIER_POLY converter( ctrlPoints );
553
554 std::vector<VECTOR2I> bezierPoints;
555 converter.GetPoly( bezierPoints, bezierMinSegLen, 16 );
556
557 result.Append( bezierPoints );
558
559 prevPt = pt3;
560 }
561 else if( str == wxS( "L" ) )
562 {
563 result.Append( ScalePos( prevPt ) );
564
565 while( i < polyData.size() - 2 && polyData.at( i + 1 ).is_number() )
566 {
567 VECTOR2D pt;
568 pt.x = ( polyData.at( ++i ) );
569 pt.y = ( polyData.at( ++i ) );
570
571 result.Append( ScalePos( pt ) );
572
573 prevPt = pt;
574 }
575 }
576 }
577 else if( val.is_number() )
578 {
579 prevPt.x = ( polyData.at( i ) );
580 prevPt.y = ( polyData.at( ++i ) );
581 }
582 }
583
584 return result;
585}
586
587
588std::unique_ptr<PAD> PCB_EASYEDAPRO_PARSER::createPAD( FOOTPRINT* aFootprint,
589 const nlohmann::json& line )
590{
591 wxString uuid = line.at( 1 );
592 int unk = line.at( 2 ).get<int>();
593 wxString netname = line.at( 3 );
594 int layer = line.at( 4 ).get<int>();
595 PCB_LAYER_ID klayer = LayerToKi( layer );
596
597 wxString padNumber = line.at( 5 );
598
599 VECTOR2D center;
600 center.x = line.at( 6 );
601 center.y = line.at( 7 );
602
603 double orientation = line.at( 8 );
604
605 nlohmann::json padHole = line.at( 9 );
606 nlohmann::json padShape = line.at( 10 );
607
608 std::unique_ptr<PAD> pad = std::make_unique<PAD>( aFootprint );
609
610 pad->SetNumber( padNumber );
611 pad->SetPosition( ScalePos( center ) );
612 pad->SetOrientationDegrees( orientation );
613
614 if( !padHole.is_null() )
615 {
616 double drill_dir = 0;
617
618 if( line.at( 14 ).is_number() )
619 drill_dir = line.at( 14 );
620
621 if( padHole.at( 0 ) == wxS( "ROUND" ) || padHole.at( 0 ) == wxS( "SLOT" ) )
622 {
623 VECTOR2D drill;
624 drill.x = padHole.at( 1 );
625 drill.y = padHole.at( 2 );
626
627 double deg = EDA_ANGLE( drill_dir, DEGREES_T ).Normalize90().AsDegrees();
628
629 if( std::abs( deg ) >= 45 )
630 std::swap( drill.x, drill.y ); // KiCad doesn't support arbitrary hole direction
631
632 if( padHole.at( 0 ) == wxS( "SLOT" ) )
633 {
634 pad->SetDrillShape( PAD_DRILL_SHAPE_OBLONG );
635 }
636
637 pad->SetDrillSize( ScaleSize( drill ) );
638 pad->SetLayerSet( PAD::PTHMask() );
639 pad->SetAttribute( PAD_ATTRIB::PTH );
640 }
641 }
642 else
643 {
644 if( klayer == F_Cu )
645 {
646 pad->SetLayerSet( PAD::SMDMask() );
647 }
648 else if( klayer == B_Cu )
649 {
650 pad->SetLayerSet( FlipLayerMask( PAD::SMDMask() ) );
651 }
652
653 pad->SetAttribute( PAD_ATTRIB::SMD );
654 }
655
656 wxString padSh = padShape.at( 0 );
657 if( padSh == wxS( "RECT" ) )
658 {
659 VECTOR2D size;
660 size.x = padShape.at( 1 );
661 size.y = padShape.at( 2 );
662 double cr_p = padShape.size() > 3 ? padShape.at( 3 ).get<double>() : 0;
663
664 pad->SetSize( ScaleSize( size ) );
665
666 if( cr_p == 0 )
667 {
668 pad->SetShape( PAD_SHAPE::RECTANGLE );
669 }
670 else
671 {
672 pad->SetShape( PAD_SHAPE::ROUNDRECT );
673 pad->SetRoundRectRadiusRatio( cr_p / 100 );
674 }
675 }
676 else if( padSh == wxS( "ELLIPSE" ) )
677 {
678 VECTOR2D size;
679 size.x = padShape.at( 1 );
680 size.y = padShape.at( 2 );
681
682 pad->SetSize( ScaleSize( size ) );
683 pad->SetShape( PAD_SHAPE::CIRCLE );
684 }
685 else if( padSh == wxS( "OVAL" ) )
686 {
687 VECTOR2D size;
688 size.x = padShape.at( 1 );
689 size.y = padShape.at( 2 );
690
691 pad->SetSize( ScaleSize( size ) );
692 pad->SetShape( PAD_SHAPE::OVAL );
693 }
694 else if( padSh == wxS( "POLY" ) )
695 {
696 pad->SetShape( PAD_SHAPE::CUSTOM );
697 pad->SetAnchorPadShape( PAD_SHAPE::CIRCLE );
698 pad->SetSize( { 1, 1 } );
699
700 nlohmann::json polyData = padShape.at( 1 );
701
702 std::vector<std::unique_ptr<PCB_SHAPE>> results =
703 ParsePoly( aFootprint, polyData, true, false );
704
705 for( auto& shape : results )
706 {
707 shape->SetLayer( klayer );
708 shape->SetWidth( 0 );
709
710 shape->Move( -pad->GetPosition() );
711
712 pad->AddPrimitive( shape.release() );
713 }
714 }
715
716 pad->SetThermalSpokeAngle( ANGLE_90 );
717
718 return std::move( pad );
719}
720
721
722FOOTPRINT* PCB_EASYEDAPRO_PARSER::ParseFootprint( const nlohmann::json& aProject,
723 const wxString& aFpUuid,
724 const std::vector<nlohmann::json>& aLines )
725{
726 std::unique_ptr<FOOTPRINT> footprintPtr = std::make_unique<FOOTPRINT>( m_board );
727 FOOTPRINT* footprint = footprintPtr.get();
728
729 const VECTOR2I defaultTextSize( pcbIUScale.mmToIU( 1.0 ), pcbIUScale.mmToIU( 1.0 ) );
730 const int defaultTextThickness( pcbIUScale.mmToIU( 0.15 ) );
731
732 for( PCB_FIELD* field : footprint->Fields() )
733 {
734 field->SetTextSize( defaultTextSize );
735 field->SetTextThickness( defaultTextThickness );
736 }
737
738 for( const nlohmann::json& line : aLines )
739 {
740 if( line.size() == 0 )
741 continue;
742
743 wxString type = line.at( 0 );
744
745 if( type == wxS( "POLY" ) || type == wxS( "PAD" ) || type == wxS( "FILL" )
746 || type == wxS( "ATTR" ) )
747 {
748 wxString uuid = line.at( 1 );
749 int unk = line.at( 2 ).get<int>();
750 wxString netname = line.at( 3 );
751 int layer = line.at( 4 ).get<int>();
752 PCB_LAYER_ID klayer = LayerToKi( layer );
753
754 if( type == wxS( "POLY" ) )
755 {
756 double thickness = ( line.at( 5 ) );
757 nlohmann::json polyData = line.at( 6 );
758
759 std::vector<std::unique_ptr<PCB_SHAPE>> results =
760 ParsePoly( footprint, polyData, false, false );
761
762 for( auto& shape : results )
763 {
764 shape->SetLayer( klayer );
765 shape->SetWidth( ScaleSize( thickness ) );
766
767 footprint->Add( shape.release(), ADD_MODE::APPEND );
768 }
769 }
770 else if( type == wxS( "PAD" ) )
771 {
772 std::unique_ptr<PAD> pad = createPAD( footprint, line );
773
774 footprint->Add( pad.release(), ADD_MODE::APPEND );
775 }
776 else if( type == wxS( "FILL" ) )
777 {
778 int layer = line.at( 4 ).get<int>();
779 PCB_LAYER_ID klayer = LayerToKi( layer );
780
781 double width = line.at( 5 );
782
783 nlohmann::json polyDataList = line.at( 7 );
784
785 if( !polyDataList.at( 0 ).is_array() )
786 polyDataList = nlohmann::json::array( { polyDataList } );
787
788 std::vector<SHAPE_LINE_CHAIN> contours;
789 for( nlohmann::json& polyData : polyDataList )
790 {
791 SHAPE_LINE_CHAIN contour = ParseContour( polyData, false );
792 contour.SetClosed( true );
793
794 contours.push_back( contour );
795 }
796
797 SHAPE_POLY_SET polySet;
798
799 for( SHAPE_LINE_CHAIN& contour : contours )
800 polySet.AddOutline( contour );
801
802 polySet.RebuildHolesFromContours();
803
804 std::unique_ptr<PCB_GROUP> group;
805
806 if( polySet.OutlineCount() > 1 )
807 group = std::make_unique<PCB_GROUP>( footprint );
808
809 BOX2I polyBBox = polySet.BBox();
810
811 for( const SHAPE_POLY_SET::POLYGON& poly : polySet.CPolygons() )
812 {
813 std::unique_ptr<PCB_SHAPE> shape =
814 std::make_unique<PCB_SHAPE>( footprint, SHAPE_T::POLY );
815
816 shape->SetFilled( true );
817 shape->SetPolyShape( poly );
818 shape->SetLayer( klayer );
819 shape->SetWidth( 0 );
820
821 if( group )
822 group->AddItem( shape.get() );
823
824 footprint->Add( shape.release(), ADD_MODE::APPEND );
825 }
826
827 if( group )
828 footprint->Add( group.release(), ADD_MODE::APPEND );
829 }
830 else if( type == wxS( "ATTR" ) )
831 {
832 EASYEDAPRO::PCB_ATTR attr = line;
833
834 if( attr.key == wxS( "Designator" ) )
835 footprint->GetField( REFERENCE_FIELD )->SetText( attr.value );
836 }
837 }
838 else if( type == wxS( "REGION" ) )
839 {
840 wxString uuid = line.at( 1 );
841 int unk = line.at( 2 ).get<int>();
842
843 int layer = line.at( 3 ).get<int>();
844 PCB_LAYER_ID klayer = LayerToKi( layer );
845
846 double width = line.at( 4 );
847 std::set<int> flags = line.at( 5 );
848 nlohmann::json polyDataList = line.at( 6 );
849
850 for( nlohmann::json& polyData : polyDataList )
851 {
852 SHAPE_POLY_SET polySet;
853
854 std::vector<std::unique_ptr<PCB_SHAPE>> results =
855 ParsePoly( nullptr, polyData, true, false );
856
857 for( auto& shape : results )
858 {
859 shape->SetFilled( true );
860 shape->TransformShapeToPolygon( polySet, klayer, 0, ARC_HIGH_DEF, ERROR_INSIDE,
861 true );
862 }
863
865
866 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>( footprint );
867
868 zone->SetIsRuleArea( true );
869 zone->SetDoNotAllowFootprints( !!flags.count( 2 ) );
870 zone->SetDoNotAllowCopperPour( !!flags.count( 7 ) || !!flags.count( 6 )
871 || !!flags.count( 8 ) );
872 zone->SetDoNotAllowPads( !!flags.count( 7 ) );
873 zone->SetDoNotAllowTracks( !!flags.count( 7 ) || !!flags.count( 5 ) );
874 zone->SetDoNotAllowVias( !!flags.count( 7 ) );
875
876 zone->SetLayer( klayer );
877 zone->Outline()->Append( polySet );
878
879 footprint->Add( zone.release(), ADD_MODE::APPEND );
880 }
881 }
882 }
883
884 if( aProject.is_object() )
885 {
886 std::map<wxString, EASYEDAPRO::PRJ_DEVICE> devicesMap = aProject.at( "devices" );
887 std::map<wxString, wxString> compAttrs;
888
889 for( auto& [devUuid, devData] : devicesMap )
890 {
891 if( auto fp = get_opt( devData.attributes, "Footprint" ) )
892 {
893 if( *fp == aFpUuid )
894 {
895 compAttrs = devData.attributes;
896 break;
897 }
898 }
899 }
900
901 wxString modelUuid, modelTitle, modelTransform;
902
903 modelUuid = get_def( compAttrs, "3D Model", "" );
904 modelTitle = get_def( compAttrs, "3D Model Title", modelUuid );
905 modelTransform = get_def( compAttrs, "3D Model Transform", "" );
906
907 fillFootprintModelInfo( footprint, modelUuid, modelTitle, modelTransform );
908 }
909
910 // Heal board outlines
911 std::vector<PCB_SHAPE*> shapes;
912 std::vector<std::unique_ptr<PCB_SHAPE>> newShapes;
913
914 for( BOARD_ITEM* item : footprint->GraphicalItems() )
915 {
916 if( !item->IsOnLayer( Edge_Cuts ) )
917 continue;
918
919 if( item->Type() == PCB_SHAPE_T )
920 shapes.push_back( static_cast<PCB_SHAPE*>( item ) );
921 }
922
923 ConnectBoardShapes( shapes, newShapes, SHAPE_JOIN_DISTANCE );
924
925 for( std::unique_ptr<PCB_SHAPE>& ptr : newShapes )
926 footprint->Add( ptr.release(), ADD_MODE::APPEND );
927
928 return footprintPtr.release();
929}
930
931
933 BOARD* aBoard, const nlohmann::json& aProject,
934 std::map<wxString, std::unique_ptr<FOOTPRINT>>& aFootprintMap,
935 const std::map<wxString, EASYEDAPRO::BLOB>& aBlobMap,
936 const std::multimap<wxString, EASYEDAPRO::POURED>& aPouredMap,
937 const std::vector<nlohmann::json>& aLines, const wxString& aFpLibName )
938{
939 std::map<wxString, std::vector<nlohmann::json>> componentLines;
940 std::map<wxString, std::vector<nlohmann::json>> ruleLines;
941
943
944 for( const nlohmann::json& line : aLines )
945 {
946 if( line.size() == 0 )
947 continue;
948
949 wxString type = line.at( 0 );
950
951 if( type == wxS( "LAYER" ) )
952 {
953 int layer = line.at( 1 );
954 PCB_LAYER_ID klayer = LayerToKi( layer );
955
956 wxString layerType = line.at( 2 );
957 wxString layerName = line.at( 3 );
958 int layerFlag = line.at( 4 );
959
960 if( layerFlag != 0 )
961 {
962 LSET blayers = aBoard->GetEnabledLayers();
963 blayers.set( klayer );
964 aBoard->SetEnabledLayers( blayers );
965 aBoard->SetLayerName( klayer, layerName );
966 }
967 }
968 else if( type == wxS( "NET" ) )
969 {
970 wxString netname = line.at( 1 );
971
972 aBoard->Add( new NETINFO_ITEM( aBoard, netname, aBoard->GetNetCount() + 1 ),
973 ADD_MODE::APPEND );
974 }
975 else if( type == wxS( "RULE" ) )
976 {
977 wxString ruleType = line.at( 1 );
978 wxString ruleName = line.at( 2 );
979 int isDefault = line.at( 3 );
980 nlohmann::json ruleData = line.at( 4 );
981
982 if( ruleType == wxS( "3" ) && isDefault ) // Track width
983 {
984 wxString units = ruleData.at( 0 );
985 double minVal = ruleData.at( 1 );
986 double optVal = ruleData.at( 2 );
987 double maxVal = ruleData.at( 3 );
988
989 bds.m_TrackMinWidth = ScaleSize( minVal );
990 }
991 else if( ruleType == wxS( "1" ) && isDefault )
992 {
993 wxString units = ruleData.at( 0 );
994 nlohmann::json table = ruleData.at( 1 );
995
996 int minVal = INT_MAX;
997 for( const std::vector<int>& arr : table )
998 {
999 for( int val : arr )
1000 {
1001 if( val < minVal )
1002 minVal = val;
1003 }
1004 }
1005
1006 bds.m_MinClearance = ScaleSize( minVal );
1007 }
1008
1009 ruleLines[ruleType].push_back( line );
1010 }
1011 else if( type == wxS( "VIA" ) || type == wxS( "LINE" ) || type == wxS( "ARC" )
1012 || type == wxS( "POLY" ) || type == wxS( "FILL" ) || type == wxS( "POUR" ) )
1013 {
1014 wxString uuid = line.at( 1 );
1015 int unk = line.at( 2 ).get<int>();
1016 wxString netname = line.at( 3 );
1017
1018 if( type == wxS( "VIA" ) )
1019 {
1020 VECTOR2D center;
1021 center.x = line.at( 5 );
1022 center.y = line.at( 6 );
1023
1024 double drill = line.at( 7 );
1025 double dia = line.at( 8 );
1026
1027 std::unique_ptr<PCB_VIA> via = std::make_unique<PCB_VIA>( aBoard );
1028
1029 via->SetPosition( ScalePos( center ) );
1030 via->SetDrill( ScaleSize( drill ) );
1031 via->SetWidth( ScaleSize( dia ) );
1032
1033 via->SetNet( aBoard->FindNet( netname ) );
1034
1035 aBoard->Add( via.release(), ADD_MODE::APPEND );
1036 }
1037 else if( type == wxS( "LINE" ) )
1038 {
1039 int layer = line.at( 4 ).get<int>();
1040 PCB_LAYER_ID klayer = LayerToKi( layer );
1041
1042 VECTOR2D start;
1043 start.x = line.at( 5 );
1044 start.y = line.at( 6 );
1045
1046 VECTOR2D end;
1047 end.x = line.at( 7 );
1048 end.y = line.at( 8 );
1049
1050 double width = line.at( 9 );
1051
1052 std::unique_ptr<PCB_TRACK> track = std::make_unique<PCB_TRACK>( aBoard );
1053
1054 track->SetLayer( klayer );
1055 track->SetStart( ScalePos( start ) );
1056 track->SetEnd( ScalePos( end ) );
1057 track->SetWidth( ScaleSize( width ) );
1058
1059 track->SetNet( aBoard->FindNet( netname ) );
1060
1061 aBoard->Add( track.release(), ADD_MODE::APPEND );
1062 }
1063 else if( type == wxS( "ARC" ) )
1064 {
1065 int layer = line.at( 4 ).get<int>();
1066 PCB_LAYER_ID klayer = LayerToKi( layer );
1067
1068 VECTOR2D start;
1069 start.x = line.at( 5 );
1070 start.y = line.at( 6 );
1071
1072 VECTOR2D end;
1073 end.x = line.at( 7 );
1074 end.y = line.at( 8 );
1075
1076 double angle = line.at( 9 );
1077 double width = line.at( 10 );
1078
1079 VECTOR2D delta = end - start;
1080 VECTOR2D mid = ( start + delta / 2 );
1081
1082 double ha = angle / 2;
1083 double hd = delta.EuclideanNorm() / 2;
1084 double cdist = hd / tan( DEG2RAD( ha ) );
1085 VECTOR2D center = mid + delta.Perpendicular().Resize( cdist );
1086
1087 SHAPE_ARC sarc;
1088 sarc.ConstructFromStartEndCenter( ScalePos( start ), ScalePos( end ),
1089 ScalePos( center ), angle >= 0, width );
1090
1091 std::unique_ptr<PCB_ARC> arc = std::make_unique<PCB_ARC>( aBoard, &sarc );
1092 arc->SetWidth( ScaleSize( width ) );
1093
1094 arc->SetLayer( klayer );
1095 arc->SetNet( aBoard->FindNet( netname ) );
1096
1097 aBoard->Add( arc.release(), ADD_MODE::APPEND );
1098 }
1099 else if( type == wxS( "FILL" ) )
1100 {
1101 int layer = line.at( 4 ).get<int>();
1102 PCB_LAYER_ID klayer = LayerToKi( layer );
1103
1104 double width = line.at( 5 );
1105
1106 nlohmann::json polyDataList = line.at( 7 );
1107
1108 if( !polyDataList.at( 0 ).is_array() )
1109 polyDataList = nlohmann::json::array( { polyDataList } );
1110
1111 std::vector<SHAPE_LINE_CHAIN> contours;
1112 for( nlohmann::json& polyData : polyDataList )
1113 {
1114 SHAPE_LINE_CHAIN contour = ParseContour( polyData, true );
1115 contour.SetClosed( true );
1116
1117 contours.push_back( contour );
1118 }
1119
1120 SHAPE_POLY_SET zoneFillPoly;
1121
1122 for( SHAPE_LINE_CHAIN& contour : contours )
1123 zoneFillPoly.AddOutline( contour );
1124
1125 zoneFillPoly.RebuildHolesFromContours();
1127
1128 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>( aBoard );
1129
1130 zone->SetNet( aBoard->FindNet( netname ) );
1131 zone->SetLayer( klayer );
1132 zone->Outline()->Append( SHAPE_RECT( zoneFillPoly.BBox() ).Outline() );
1133 zone->SetFilledPolysList( klayer, zoneFillPoly );
1134 zone->SetAssignedPriority( 500 );
1135 zone->SetIsFilled( true );
1136 zone->SetNeedRefill( false );
1137
1138 zone->SetLocalClearance( bds.m_MinClearance );
1139 zone->SetMinThickness( bds.m_TrackMinWidth );
1140
1141 aBoard->Add( zone.release(), ADD_MODE::APPEND );
1142 }
1143 else if( type == wxS( "POLY" ) )
1144 {
1145 int layer = line.at( 4 );
1146 PCB_LAYER_ID klayer = LayerToKi( layer );
1147
1148 double thickness = line.at( 5 );
1149 nlohmann::json polyData = line.at( 6 );
1150
1151 std::vector<std::unique_ptr<PCB_SHAPE>> results =
1152 ParsePoly( aBoard, polyData, false, false );
1153
1154 for( auto& shape : results )
1155 {
1156 shape->SetLayer( klayer );
1157 shape->SetWidth( ScaleSize( thickness ) );
1158
1159 aBoard->Add( shape.release(), ADD_MODE::APPEND );
1160 }
1161 }
1162 else if( type == wxS( "POUR" ) )
1163 {
1164 int layer = line.at( 4 ).get<int>();
1165 PCB_LAYER_ID klayer = LayerToKi( layer );
1166
1167 double lineWidth = line.at( 5 ); // Doesn't matter
1168 wxString pourname = line.at( 6 );
1169 int fillOrder = line.at( 7 ).get<int>();
1170 nlohmann::json polyDataList = line.at( 8 );
1171
1172 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>( aBoard );
1173
1174 zone->SetNet( aBoard->FindNet( netname ) );
1175 zone->SetLayer( klayer );
1176 zone->SetAssignedPriority( 500 - fillOrder );
1177 zone->SetLocalClearance( bds.m_MinClearance );
1178 zone->SetMinThickness( bds.m_TrackMinWidth );
1179
1180 for( nlohmann::json& polyData : polyDataList )
1181 {
1182 SHAPE_LINE_CHAIN contour = ParseContour( polyData, false );
1183 contour.SetClosed( true );
1184
1185 zone->Outline()->Append( contour );
1186 }
1187
1188 wxASSERT( zone->Outline()->OutlineCount() == 1 );
1189
1190 SHAPE_POLY_SET fillPolySet;
1191 SHAPE_POLY_SET thermalSpokes;
1192 int entryId = 0;
1193
1195 {
1196 auto range = aPouredMap.equal_range( uuid );
1197 for( auto& it = range.first; it != range.second; ++it )
1198 {
1199 const EASYEDAPRO::POURED& poured = it->second;
1200 int unki = poured.unki;
1201
1202 SHAPE_POLY_SET thisPoly;
1203
1204 for( int dataId = 0; dataId < poured.polyData.size(); dataId++ )
1205 {
1206 const nlohmann::json& fillData = poured.polyData[dataId];
1207 const double ptScale = 10;
1208
1209 SHAPE_LINE_CHAIN contour =
1210 ParseContour( fillData, false, ARC_HIGH_DEF / ptScale );
1211
1212 // Scale the fill
1213 for( int i = 0; i < contour.PointCount(); i++ )
1214 contour.SetPoint( i, contour.GetPoint( i ) * ptScale );
1215
1216 if( poured.isPoly )
1217 {
1218 contour.SetClosed( true );
1219
1220 // The contour can be self-intersecting
1221 SHAPE_POLY_SET simple( contour );
1223
1224 if( dataId == 0 )
1225 {
1226 thisPoly.Append( simple );
1227 }
1228 else
1229 {
1230 thisPoly.BooleanSubtract( simple,
1232 }
1233 }
1234 else
1235 {
1236 const int thermalWidth = pcbIUScale.mmToIU( 0.2 ); // Generic
1237
1238 for( int segId = 0; segId < contour.SegmentCount(); segId++ )
1239 {
1240 const SEG& seg = contour.CSegment( segId );
1241
1242 TransformOvalToPolygon( thermalSpokes, seg.A, seg.B,
1243 thermalWidth, ARC_LOW_DEF,
1244 ERROR_INSIDE );
1245 }
1246 }
1247 }
1248
1249 fillPolySet.Append( thisPoly );
1250
1251 entryId++;
1252 }
1253
1254 if( !fillPolySet.IsEmpty() )
1255 {
1257
1258 const int strokeWidth = pcbIUScale.MilsToIU( 8 ); // Seems to be 8 mils
1259
1260 fillPolySet.Inflate( strokeWidth / 2, CORNER_STRATEGY::ROUND_ALL_CORNERS,
1261 ARC_HIGH_DEF, false );
1262
1263 fillPolySet.BooleanAdd( thermalSpokes, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
1264
1266
1267 zone->SetFilledPolysList( klayer, fillPolySet );
1268 zone->SetNeedRefill( false );
1269 zone->SetIsFilled( true );
1270 }
1271 }
1272
1273 aBoard->Add( zone.release(), ADD_MODE::APPEND );
1274 }
1275 }
1276 else if( type == wxS( "TEARDROP" ) )
1277 {
1278 wxString uuid = line.at( 1 );
1279 wxString netname = line.at( 2 );
1280 int layer = line.at( 3 ).get<int>();
1281 PCB_LAYER_ID klayer = LayerToKi( layer );
1282
1283 nlohmann::json polyData = line.at( 4 );
1284
1285 SHAPE_LINE_CHAIN contour = ParseContour( polyData, false );
1286 contour.SetClosed( true );
1287
1288 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>( aBoard );
1289
1290 zone->SetNet( aBoard->FindNet( netname ) );
1291 zone->SetLayer( klayer );
1292 zone->Outline()->Append( contour );
1293 zone->SetFilledPolysList( klayer, contour );
1294 zone->SetNeedRefill( false );
1295 zone->SetIsFilled( true );
1296
1297 zone->SetAssignedPriority( 600 );
1298 zone->SetLocalClearance( 0 );
1299 zone->SetMinThickness( 0 );
1300 zone->SetTeardropAreaType( TEARDROP_TYPE::TD_UNSPECIFIED );
1301
1302 aBoard->Add( zone.release(), ADD_MODE::APPEND );
1303 }
1304 else if( type == wxS( "REGION" ) )
1305 {
1306 wxString uuid = line.at( 1 );
1307 int unk = line.at( 2 ).get<int>();
1308
1309 int layer = line.at( 3 ).get<int>();
1310 PCB_LAYER_ID klayer = LayerToKi( layer );
1311
1312 double width = line.at( 4 );
1313 std::set<int> flags = line.at( 5 );
1314 nlohmann::json polyDataList = line.at( 6 );
1315
1316 for( nlohmann::json& polyData : polyDataList )
1317 {
1318 SHAPE_LINE_CHAIN contour = ParseContour( polyData, false );
1319 contour.SetClosed( true );
1320
1321 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>( aBoard );
1322
1323 zone->SetIsRuleArea( true );
1324 zone->SetDoNotAllowFootprints( !!flags.count( 2 ) );
1325 zone->SetDoNotAllowCopperPour( !!flags.count( 7 ) || !!flags.count( 6 )
1326 || !!flags.count( 8 ) );
1327 zone->SetDoNotAllowPads( !!flags.count( 7 ) );
1328 zone->SetDoNotAllowTracks( !!flags.count( 7 ) || !!flags.count( 5 ) );
1329 zone->SetDoNotAllowVias( !!flags.count( 7 ) );
1330
1331 zone->SetLayer( klayer );
1332 zone->Outline()->Append( contour );
1333
1334 aBoard->Add( zone.release(), ADD_MODE::APPEND );
1335 }
1336 }
1337 else if( type == wxS( "PAD" ) )
1338 {
1339 wxString netname = line.at( 3 );
1340
1341 std::unique_ptr<FOOTPRINT> footprint = std::make_unique<FOOTPRINT>( aBoard );
1342 std::unique_ptr<PAD> pad = createPAD( footprint.get(), line );
1343
1344 pad->SetNet( aBoard->FindNet( netname ) );
1345
1346 VECTOR2I pos = pad->GetPosition();
1347 EDA_ANGLE orient = pad->GetOrientation();
1348
1349 pad->SetPosition( VECTOR2I() );
1350 pad->SetOrientation( ANGLE_0 );
1351
1352 footprint->Add( pad.release(), ADD_MODE::APPEND );
1353 footprint->SetPosition( pos );
1354 footprint->SetOrientation( orient );
1355
1356 wxString fpName = wxS( "Pad_" ) + line.at( 1 ).get<wxString>();
1357 LIB_ID fpID = EASYEDAPRO::ToKiCadLibID( wxEmptyString, fpName );
1358
1359 footprint->SetFPID( fpID );
1360 footprint->Reference().SetVisible( true );
1361 footprint->Value().SetVisible( true );
1362 footprint->AutoPositionFields();
1363
1364 aBoard->Add( footprint.release(), ADD_MODE::APPEND );
1365 }
1366 else if( type == wxS( "IMAGE" ) )
1367 {
1368 wxString uuid = line.at( 1 );
1369 int unk = line.at( 2 ).get<int>();
1370
1371 int layer = line.at( 3 ).get<int>();
1372 PCB_LAYER_ID klayer = LayerToKi( layer );
1373
1374 VECTOR2D start( line.at( 4 ), line.at( 5 ) );
1375 VECTOR2D size( line.at( 6 ), line.at( 7 ) );
1376
1377 double angle = line.at( 8 ); // from top left corner
1378 int mirror = line.at( 9 );
1379 nlohmann::json polyDataList = line.at( 10 );
1380
1381 BOX2I bbox;
1382 std::vector<SHAPE_LINE_CHAIN> contours;
1383 for( nlohmann::json& polyData : polyDataList )
1384 {
1385 SHAPE_LINE_CHAIN contour = ParseContour( polyData, false );
1386 contour.SetClosed( true );
1387
1388 contours.push_back( contour );
1389
1390 bbox.Merge( contour.BBox() );
1391 }
1392
1393 VECTOR2D scale( ScaleSize( size.x ) / bbox.GetSize().x,
1394 ScaleSize( size.y ) / bbox.GetSize().y );
1395
1396 SHAPE_POLY_SET polySet;
1397
1398 for( SHAPE_LINE_CHAIN& contour : contours )
1399 {
1400 for( int i = 0; i < contour.PointCount(); i++ )
1401 {
1402 VECTOR2I pt = contour.CPoint( i );
1403 contour.SetPoint( i, VECTOR2I( pt.x * scale.x, pt.y * scale.y ) );
1404 }
1405
1406 polySet.AddOutline( contour );
1407 }
1408
1409 polySet.RebuildHolesFromContours();
1410
1411 std::unique_ptr<PCB_GROUP> group;
1412
1413 if( polySet.OutlineCount() > 1 )
1414 group = std::make_unique<PCB_GROUP>( aBoard );
1415
1416 BOX2I polyBBox = polySet.BBox();
1417
1418 for( const SHAPE_POLY_SET::POLYGON& poly : polySet.CPolygons() )
1419 {
1420 std::unique_ptr<PCB_SHAPE> shape =
1421 std::make_unique<PCB_SHAPE>( aBoard, SHAPE_T::POLY );
1422
1423 shape->SetFilled( true );
1424 shape->SetPolyShape( poly );
1425 shape->SetLayer( klayer );
1426 shape->SetWidth( 0 );
1427
1428 shape->Move( ScalePos( start ) - polyBBox.GetOrigin() );
1429 shape->Rotate( ScalePos( start ), EDA_ANGLE( angle, DEGREES_T ) );
1430
1431 if( IsBackLayer( klayer ) ^ !!mirror )
1432 shape->Mirror( ScalePos( start ), !IsBackLayer( klayer ) );
1433
1434 if( group )
1435 group->AddItem( shape.get() );
1436
1437 aBoard->Add( shape.release(), ADD_MODE::APPEND );
1438 }
1439
1440 if( group )
1441 aBoard->Add( group.release(), ADD_MODE::APPEND );
1442 }
1443 else if( type == wxS( "STRING" ) )
1444 {
1445 wxString uuid = line.at( 1 );
1446 int unk = line.at( 2 );
1447
1448 int layer = line.at( 3 ).get<int>();
1449 PCB_LAYER_ID klayer = LayerToKi( layer );
1450
1451 VECTOR2D location( line.at( 4 ), line.at( 5 ) );
1452 wxString string = line.at( 6 );
1453 wxString font = line.at( 7 );
1454
1455 double height = line.at( 8 );
1456 double strokew = line.at( 9 );
1457
1458 int align = line.at( 12 );
1459 double angle = line.at( 13 );
1460 int inverted = line.at( 14 );
1461 int mirror = line.at( 16 );
1462
1463 PCB_TEXT* text = new PCB_TEXT( aBoard );
1464
1465 text->SetText( string );
1466 text->SetLayer( klayer );
1467 text->SetPosition( ScalePos( location ) );
1468 text->SetIsKnockout( inverted );
1469 text->SetTextThickness( ScaleSize( strokew ) );
1470 text->SetTextSize( VECTOR2D( ScaleSize( height * 0.6 ), ScaleSize( height * 0.7 ) ) );
1471
1472 if( font != wxS( "default" ) )
1473 {
1474 text->SetFont( KIFONT::FONT::GetFont( font ) );
1475 //text->SetupRenderCache( text->GetShownText(), EDA_ANGLE( angle, DEGREES_T ) );
1476
1477 //text->AddRenderCacheGlyph();
1478 // TODO: import geometry cache
1479 }
1480
1481 AlignText( text, align );
1482
1483 if( IsBackLayer( klayer ) ^ !!mirror )
1484 {
1485 text->SetMirrored( true );
1486 text->SetTextAngleDegrees( -angle );
1487 }
1488 else
1489 {
1490 text->SetTextAngleDegrees( angle );
1491 }
1492
1493 aBoard->Add( text, ADD_MODE::APPEND );
1494 }
1495 else if( type == wxS( "COMPONENT" ) )
1496 {
1497 wxString compId = line.at( 1 );
1498 componentLines[compId].push_back( line );
1499 }
1500 else if( type == wxS( "ATTR" ) )
1501 {
1502 wxString compId = line.at( 3 );
1503 componentLines[compId].push_back( line );
1504 }
1505 else if( type == wxS( "PAD_NET" ) )
1506 {
1507 wxString compId = line.at( 1 );
1508 componentLines[compId].push_back( line );
1509 }
1510 }
1511
1512 for( auto const& [compId, lines] : componentLines )
1513 {
1514 wxString deviceId;
1515 wxString fpIdOverride;
1516 wxString fpDesignator;
1517 std::map<wxString, wxString> localCompAttribs;
1518
1519 for( auto& line : lines )
1520 {
1521 if( line.size() == 0 )
1522 continue;
1523
1524 wxString type = line.at( 0 );
1525
1526 if( type == wxS( "COMPONENT" ) )
1527 {
1528 localCompAttribs = line.at( 7 );
1529 }
1530 else if( type == wxS( "ATTR" ) )
1531 {
1532 EASYEDAPRO::PCB_ATTR attr = line;
1533
1534 if( attr.key == wxS( "Device" ) )
1535 deviceId = attr.value;
1536
1537 else if( attr.key == wxS( "Footprint" ) )
1538 fpIdOverride = attr.value;
1539
1540 else if( attr.key == wxS( "Designator" ) )
1541 fpDesignator = attr.value;
1542 }
1543 }
1544
1545 if( deviceId.empty() )
1546 continue;
1547
1548 nlohmann::json compAttrs = aProject.at( "devices" ).at( deviceId ).at( "attributes" );
1549
1550 wxString fpId;
1551
1552 if( !fpIdOverride.IsEmpty() )
1553 fpId = fpIdOverride;
1554 else
1555 fpId = compAttrs.at( "Footprint" ).get<wxString>();
1556
1557 auto it = aFootprintMap.find( fpId );
1558 if( it == aFootprintMap.end() )
1559 {
1560 wxLogError( "Footprint of '%s' with uuid '%s' not found.", fpDesignator, fpId );
1561 continue;
1562 }
1563
1564 std::unique_ptr<FOOTPRINT>& footprintOrig = it->second;
1565 std::unique_ptr<FOOTPRINT> footprint( static_cast<FOOTPRINT*>( footprintOrig->Clone() ) );
1566
1567 wxString modelUuid, modelTitle, modelTransform;
1568
1569 if( auto val = get_opt( localCompAttribs, "3D Model" ) )
1570 modelUuid = *val;
1571 else
1572 modelUuid = compAttrs.value<wxString>( "3D Model", "" );
1573
1574 if( auto val = get_opt( localCompAttribs, "3D Model Title" ) )
1575 modelTitle = val->Trim();
1576 else
1577 modelTitle = compAttrs.value<wxString>( "3D Model Title", modelUuid ).Trim();
1578
1579 if( auto val = get_opt( localCompAttribs, "3D Model Transform" ) )
1580 modelTransform = *val;
1581 else
1582 modelTransform = compAttrs.value<wxString>( "3D Model Transform", "" );
1583
1584 fillFootprintModelInfo( footprint.get(), modelUuid, modelTitle, modelTransform );
1585
1586 footprint->SetParent( aBoard );
1587
1588 for( auto& line : lines )
1589 {
1590 if( line.size() == 0 )
1591 continue;
1592
1593 wxString type = line.at( 0 );
1594
1595 if( type == wxS( "COMPONENT" ) )
1596 {
1597 int layer = line.at( 3 );
1598 PCB_LAYER_ID klayer = LayerToKi( layer );
1599
1600 VECTOR2D center( line.at( 4 ), line.at( 5 ) );
1601
1602 double orient = line.at( 6 );
1603 //std::map<wxString, wxString> props = line.at( 7 );
1604
1605 if( klayer == B_Cu )
1606 footprint->Flip( footprint->GetPosition(), false );
1607
1608 footprint->SetOrientationDegrees( orient );
1609 footprint->SetPosition( ScalePos( center ) );
1610 }
1611 else if( type == wxS( "ATTR" ) )
1612 {
1613 EASYEDAPRO::PCB_ATTR attr = line;
1614
1615 PCB_LAYER_ID klayer = LayerToKi( attr.layer );
1616
1617 PCB_TEXT* text = nullptr;
1618 bool add = false;
1619
1620 if( attr.key == wxS( "Designator" ) )
1621 {
1622 if( attr.key == wxS( "Designator" ) )
1623 {
1624 text = footprint->GetField( REFERENCE_FIELD );
1625 }
1626 else
1627 {
1628 text = new PCB_TEXT( footprint.get() );
1629 add = true;
1630 }
1631
1632 if( attr.fontName != wxS( "default" ) )
1633 text->SetFont( KIFONT::FONT::GetFont( attr.fontName ) );
1634
1635 if( attr.valVisible && attr.keyVisible )
1636 {
1637 text->SetText( attr.key + ':' + attr.value );
1638 }
1639 else if( attr.keyVisible )
1640 {
1641 text->SetText( attr.key );
1642 }
1643 else
1644 {
1645 text->SetText( attr.value );
1646 }
1647
1648 text->SetVisible( attr.keyVisible || attr.valVisible );
1649 text->SetLayer( klayer );
1650 text->SetPosition( ScalePos( attr.position ) );
1651 text->SetTextAngleDegrees( footprint->IsFlipped() ? -attr.rotation
1652 : attr.rotation );
1653 text->SetIsKnockout( attr.inverted );
1654 text->SetTextThickness( ScaleSize( attr.strokeWidth ) );
1655 text->SetTextSize( VECTOR2D( ScaleSize( attr.height * 0.55 ),
1656 ScaleSize( attr.height * 0.6 ) ) );
1657
1658 AlignText( text, attr.textOrigin );
1659
1660 if( add )
1661 footprint->Add( text, ADD_MODE::APPEND );
1662 }
1663 }
1664 else if( type == wxS( "PAD_NET" ) )
1665 {
1666 wxString padNumber = line.at( 2 );
1667 wxString padNet = line.at( 3 );
1668
1669 PAD* pad = footprint->FindPadByNumber( padNumber );
1670 if( pad )
1671 {
1672 pad->SetNet( aBoard->FindNet( padNet ) );
1673 }
1674 else
1675 {
1676 // Not a pad
1677 }
1678 }
1679 }
1680
1681 aBoard->Add( footprint.release(), ADD_MODE::APPEND );
1682 }
1683
1684 // Heal board outlines
1685 std::vector<PCB_SHAPE*> shapes;
1686 std::vector<std::unique_ptr<PCB_SHAPE>> newShapes;
1687
1688 for( BOARD_ITEM* item : aBoard->Drawings() )
1689 {
1690 if( !item->IsOnLayer( Edge_Cuts ) )
1691 continue;
1692
1693 if( item->Type() == PCB_SHAPE_T )
1694 shapes.push_back( static_cast<PCB_SHAPE*>( item ) );
1695 }
1696
1697 ConnectBoardShapes( shapes, newShapes, SHAPE_JOIN_DISTANCE );
1698
1699 for( std::unique_ptr<PCB_SHAPE>& ptr : newShapes )
1700 aBoard->Add( ptr.release(), ADD_MODE::APPEND );
1701
1702 // Center the board
1703 BOX2I outlineBbox = aBoard->ComputeBoundingBox( true );
1704 PAGE_INFO pageInfo = aBoard->GetPageSettings();
1705
1706 VECTOR2D pageCenter( pcbIUScale.MilsToIU( pageInfo.GetWidthMils() / 2 ),
1707 pcbIUScale.MilsToIU( pageInfo.GetHeightMils() / 2 ) );
1708
1709 VECTOR2D offset = pageCenter - outlineBbox.GetCenter();
1710
1711 int alignGrid = pcbIUScale.mmToIU( 10 );
1712 offset.x = KiROUND( offset.x / alignGrid ) * alignGrid;
1713 offset.y = KiROUND( offset.y / alignGrid ) * alignGrid;
1714
1715 aBoard->Move( offset );
1716 bds.SetAuxOrigin( offset );
1717}
constexpr int ARC_HIGH_DEF
Definition: base_units.h:121
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:109
constexpr int ARC_LOW_DEF
Definition: base_units.h:120
Bezier curves to polygon converter.
Definition: bezier_curves.h:38
void GetPoly(std::vector< VECTOR2I > &aOutput, int aMinSegLen=0, int aMaxSegCount=32)
Convert a Bezier curve to a polygon.
Container for design settings for a BOARD object.
void SetAuxOrigin(const VECTOR2I &aOrigin)
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:77
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:259
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:276
LSET GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition: board.cpp:649
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition: board.cpp:855
void SetEnabledLayers(LSET aLayerMask)
A proxy function that calls the correspondent function in m_BoardSettings.
Definition: board.cpp:669
const PAGE_INFO & GetPageSettings() const
Definition: board.h:649
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition: board.cpp:1642
bool SetLayerName(PCB_LAYER_ID aLayer, const wxString &aLayerName)
Changes the name of the layer given by aLayer.
Definition: board.cpp:552
void Move(const VECTOR2I &aMoveVector) override
Move this object.
Definition: board.cpp:462
BOX2I ComputeBoundingBox(bool aBoardEdgesOnly=false) const
Calculate the bounding box containing all board items (or board edge segments).
Definition: board.cpp:1389
DRAWINGS & Drawings()
Definition: board.h:321
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:766
unsigned GetNetCount() const
Definition: board.h:858
const Vec & GetOrigin() const
Definition: box2.h:184
const Vec GetCenter() const
Definition: box2.h:196
const Vec & GetSize() const
Definition: box2.h:180
BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition: box2.h:589
EDA_ANGLE Normalize90()
Definition: eda_angle.h:277
double AsDegrees() const
Definition: eda_angle.h:149
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:80
virtual void SetVisible(bool aVisible)
Definition: eda_text.cpp:229
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:183
int GetFieldCount() const
Return the number of fields in this symbol.
Definition: footprint.h:674
PCB_FIELD * GetFieldByName(const wxString &aFieldName)
Return a field in this symbol.
Definition: footprint.cpp:294
PCB_FIELD * AddField(const PCB_FIELD &aField)
Add a field to the symbol.
Definition: footprint.cpp:336
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition: footprint.cpp:724
std::vector< FP_3DMODEL > & Models()
Definition: footprint.h:202
PCB_FIELDS & Fields()
Definition: footprint.h:185
PCB_FIELD * GetField(MANDATORY_FIELD_T aFieldType)
Return a mandatory field in this symbol.
Definition: footprint.cpp:260
DRAWINGS & GraphicalItems()
Definition: footprint.h:191
VECTOR3D m_Offset
3D model offset (mm)
Definition: footprint.h:98
VECTOR3D m_Rotation
3D model rotation (degrees)
Definition: footprint.h:97
wxString m_Filename
The 3D shape filename in 3D library.
Definition: footprint.h:100
static FONT * GetFont(const wxString &aFontName=wxEmptyString, bool aBold=false, bool aItalic=false)
Definition: font.cpp:146
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:49
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:556
Handle the data for a net.
Definition: netinfo.h:56
Definition: pad.h:59
static LSET PTHMask()
layer set for a through hole pad
Definition: pad.cpp:194
static LSET SMDMask()
layer set for a SMD pad on Front layer
Definition: pad.cpp:201
Describe the page size and margins of a paper page on which to eventually print or plot.
Definition: page_info.h:58
double GetHeightMils() const
Definition: page_info.h:140
double GetWidthMils() const
Definition: page_info.h:135
PCB_LAYER_ID LayerToKi(int aLayer)
FOOTPRINT * ParseFootprint(const nlohmann::json &aProject, const wxString &aFpUuid, const std::vector< nlohmann::json > &aLines)
static double Convert(wxString aValue)
std::vector< std::unique_ptr< PCB_SHAPE > > ParsePoly(BOARD_ITEM_CONTAINER *aContainer, nlohmann::json polyData, bool aClosed, bool aInFill) const
SHAPE_LINE_CHAIN ParseContour(nlohmann::json polyData, bool aInFill, double aArcAccuracy=SHAPE_ARC::DefaultAccuracyForPCB()) const
PCB_EASYEDAPRO_PARSER(BOARD *aBoard, PROGRESS_REPORTER *aProgressReporter)
static VECTOR2< T > ScalePos(VECTOR2< T > aValue)
static T ScaleSize(T aValue)
void ParseBoard(BOARD *aBoard, const nlohmann::json &aProject, std::map< wxString, std::unique_ptr< FOOTPRINT > > &aFootprintMap, const std::map< wxString, EASYEDAPRO::BLOB > &aBlobMap, const std::multimap< wxString, EASYEDAPRO::POURED > &aPouredMap, const std::vector< nlohmann::json > &aLines, const wxString &aFpLibName)
void fillFootprintModelInfo(FOOTPRINT *footprint, const wxString &modelUuid, const wxString &modelTitle, const wxString &modelTransform) const
std::unique_ptr< PAD > createPAD(FOOTPRINT *aFootprint, const nlohmann::json &line)
A progress reporter interface for use in multi-threaded environments.
Definition: seg.h:42
VECTOR2I A
Definition: seg.h:49
VECTOR2I B
Definition: seg.h:50
SHAPE_ARC & ConstructFromStartEndCenter(const VECTOR2I &aStart, const VECTOR2I &aEnd, const VECTOR2I &aCenter, bool aClockwise=false, double aWidth=0)
Constructs this arc from the given start, end and center.
Definition: shape_arc.cpp:210
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
virtual const VECTOR2I GetPoint(int aIndex) const override
void SetPoint(int aIndex, const VECTOR2I &aPos)
Move a point to a specific location.
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
int PointCount() const
Return the number of points (vertices) in this line chain.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
int SegmentCount() const
Return the number of segments in this line chain.
const SEG CSegment(int aIndex) const
Return a constant copy of the aIndex segment in the line chain.
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
SEG Segment(int aIndex)
Return a copy of the aIndex-th segment in the line chain.
Represent a set of closed polygons.
void BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset difference For aFastMode meaning, see function booleanOp.
void Fracture(POLYGON_MODE aFastMode)
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
void BooleanAdd(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset union For aFastMode meaning, see function booleanOp.
void Inflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, bool aSimplify=false)
Perform outline inflation/deflation.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
std::vector< SHAPE_LINE_CHAIN > POLYGON
represents a single polygon outline with holes.
void Simplify(POLYGON_MODE aFastMode)
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections) For aFastMo...
void RebuildHolesFromContours()
Extract all contours from this polygon set, then recreate polygons with holes.
int OutlineCount() const
Return the number of outlines in the set.
const std::vector< POLYGON > & CPolygons() const
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
const SHAPE_LINE_CHAIN Outline() const
Definition: shape_rect.h:179
T y
Definition: vector3.h:63
T z
Definition: vector3.h:64
T x
Definition: vector3.h:62
void TransformCircleToPolygon(SHAPE_LINE_CHAIN &aBuffer, const VECTOR2I &aCenter, int aRadius, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a circle to a polygon, using multiple straight lines.
void TransformRoundChamferedRectToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aPosition, const VECTOR2I &aSize, const EDA_ANGLE &aRotation, int aCornerRadius, double aChamferRatio, int aChamferCorners, int aInflate, int aError, ERROR_LOC aErrorLoc)
Convert a rectangle with rounded corners and/or chamfered corners to a polygon.
void TransformOvalToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aWidth, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a oblong shape to a polygon, using multiple segments.
#define _(s)
@ DEGREES_T
Definition: eda_angle.h:31
static constexpr EDA_ANGLE & ANGLE_90
Definition: eda_angle.h:439
static constexpr EDA_ANGLE & ANGLE_0
Definition: eda_angle.h:437
void ConnectBoardShapes(std::vector< PCB_SHAPE * > &aShapeList, std::vector< std::unique_ptr< PCB_SHAPE > > &aNewShapes, int aChainingEpsilon)
Connects shapes to each other, making continious contours (adjacent shapes will have a common vertex)...
@ ERROR_INSIDE
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:39
bool IsBackLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a back layer.
Definition: layer_ids.h:950
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ In22_Cu
Definition: layer_ids.h:87
@ In11_Cu
Definition: layer_ids.h:76
@ In29_Cu
Definition: layer_ids.h:94
@ In30_Cu
Definition: layer_ids.h:95
@ In17_Cu
Definition: layer_ids.h:82
@ Edge_Cuts
Definition: layer_ids.h:114
@ Dwgs_User
Definition: layer_ids.h:110
@ F_Paste
Definition: layer_ids.h:102
@ In9_Cu
Definition: layer_ids.h:74
@ Cmts_User
Definition: layer_ids.h:111
@ User_6
Definition: layer_ids.h:129
@ User_7
Definition: layer_ids.h:130
@ In19_Cu
Definition: layer_ids.h:84
@ In7_Cu
Definition: layer_ids.h:72
@ In28_Cu
Definition: layer_ids.h:93
@ In26_Cu
Definition: layer_ids.h:91
@ B_Mask
Definition: layer_ids.h:107
@ B_Cu
Definition: layer_ids.h:96
@ User_5
Definition: layer_ids.h:128
@ F_Mask
Definition: layer_ids.h:108
@ In21_Cu
Definition: layer_ids.h:86
@ In23_Cu
Definition: layer_ids.h:88
@ B_Paste
Definition: layer_ids.h:101
@ In15_Cu
Definition: layer_ids.h:80
@ In2_Cu
Definition: layer_ids.h:67
@ F_Fab
Definition: layer_ids.h:121
@ In10_Cu
Definition: layer_ids.h:75
@ F_SilkS
Definition: layer_ids.h:105
@ In4_Cu
Definition: layer_ids.h:69
@ Eco2_User
Definition: layer_ids.h:113
@ In16_Cu
Definition: layer_ids.h:81
@ In24_Cu
Definition: layer_ids.h:89
@ In1_Cu
Definition: layer_ids.h:66
@ User_3
Definition: layer_ids.h:126
@ User_1
Definition: layer_ids.h:124
@ B_SilkS
Definition: layer_ids.h:104
@ In13_Cu
Definition: layer_ids.h:78
@ User_4
Definition: layer_ids.h:127
@ In8_Cu
Definition: layer_ids.h:73
@ In14_Cu
Definition: layer_ids.h:79
@ User_2
Definition: layer_ids.h:125
@ In12_Cu
Definition: layer_ids.h:77
@ In27_Cu
Definition: layer_ids.h:92
@ In6_Cu
Definition: layer_ids.h:71
@ In5_Cu
Definition: layer_ids.h:70
@ In3_Cu
Definition: layer_ids.h:68
@ In20_Cu
Definition: layer_ids.h:85
@ F_Cu
Definition: layer_ids.h:65
@ In18_Cu
Definition: layer_ids.h:83
@ In25_Cu
Definition: layer_ids.h:90
@ B_Fab
Definition: layer_ids.h:120
LSET FlipLayerMask(LSET aMask, int aCopperLayersCount)
Calculate the mask layer when flipping a footprint.
Definition: lset.cpp:599
wxString get_def(const std::map< wxString, wxString > &aMap, const char *aKey, const char *aDefval="")
Definition: map_helpers.h:64
std::optional< V > get_opt(const std::map< wxString, V > &aMap, const wxString &aKey)
Definition: map_helpers.h:34
LIB_ID ToKiCadLibID(const wxString &aLibName, const wxString &aLibReference)
static const bool IMPORT_POURED
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:426
@ PAD_DRILL_SHAPE_OBLONG
Definition: pad_shapes.h:71
static const wxString MODEL_SIZE_KEY
static const int SHAPE_JOIN_DISTANCE
static void AlignText(EDA_TEXT *text, int align)
static const wxString MODEL_SIZE_KEY
static const int SHAPE_JOIN_DISTANCE
static const wxString QUERY_MODEL_UUID_KEY
Class to handle a set of BOARD_ITEMs.
static bool addSegment(VRML_LAYER &model, IDF_SEGMENT *seg, int icont, int iseg)
const int scale
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
nlohmann::json polyData
constexpr double IUTomm(int iu) const
Definition: base_units.h:87
constexpr int MilsToIU(int mils) const
Definition: base_units.h:94
constexpr int mmToIU(double mm) const
Definition: base_units.h:89
@ REFERENCE_FIELD
Field Reference of part, i.e. "IC21".
constexpr int delta
@ GR_TEXT_H_ALIGN_CENTER
@ GR_TEXT_H_ALIGN_RIGHT
@ GR_TEXT_H_ALIGN_LEFT
@ GR_TEXT_V_ALIGN_BOTTOM
@ GR_TEXT_V_ALIGN_CENTER
@ GR_TEXT_V_ALIGN_TOP
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition: trigo.cpp:228
double DEG2RAD(double deg)
Definition: trigo.h:201
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition: typeinfo.h:88
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:85
VECTOR2< double > VECTOR2D
Definition: vector2d.h:587
VECTOR2< int > VECTOR2I
Definition: vector2d.h:588