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