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 <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#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
88{
89}
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 User_2; // Component shape layer
143 case 49: return User_3; // 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
203void PCB_IO_EASYEDAPRO_PARSER::fillFootprintModelInfo( FOOTPRINT* footprint, const wxString& modelUuid,
204 const wxString& modelTitle,
205 const wxString& modelTransform ) const
206{
207 // TODO: make this path configurable?
208 const wxString easyedaModelDir = wxS( "EASYEDA_MODELS" );
209 const wxString kicadModelPrefix = wxS( "${KIPRJMOD}/" ) + easyedaModelDir + wxS( "/" );
210
211 VECTOR3D kmodelOffset;
212 VECTOR3D kmodelRotation;
213
214 if( !modelUuid.IsEmpty() && !footprint->GetFieldByName( QUERY_MODEL_UUID_KEY ) )
215 {
216 PCB_FIELD field( footprint, footprint->GetNextFieldId(), QUERY_MODEL_UUID_KEY );
217 field.SetLayer( Cmts_User );
218 field.SetVisible( false );
219 field.SetText( modelUuid );
220 footprint->AddField( field );
221 }
222
223 if( !modelTransform.IsEmpty() && !footprint->GetFieldByName( MODEL_SIZE_KEY ) )
224 {
225 wxArrayString arr = wxSplit( modelTransform, ',', '\0' );
226
227 double fitXmm = pcbIUScale.IUTomm( ScaleSize( Convert( arr[0] ) ) );
228 double fitYmm = pcbIUScale.IUTomm( ScaleSize( Convert( arr[1] ) ) );
229
230 if( fitXmm > 0.0 && fitYmm > 0.0 )
231 {
232 PCB_FIELD field( footprint, footprint->GetNextFieldId(), MODEL_SIZE_KEY );
233 field.SetLayer( Cmts_User );
234 field.SetVisible( false );
235 field.SetText( wxString::FromCDouble( fitXmm ) + wxS( " " )
236 + wxString::FromCDouble( fitYmm ) );
237 footprint->AddField( field );
238 }
239
240 kmodelRotation.z = -Convert( arr[3] );
241 kmodelRotation.x = -Convert( arr[4] );
242 kmodelRotation.y = -Convert( arr[5] );
243
244 kmodelOffset.x = pcbIUScale.IUTomm( ScaleSize( Convert( arr[6] ) ) );
245 kmodelOffset.y = pcbIUScale.IUTomm( ScaleSize( Convert( arr[7] ) ) );
246 kmodelOffset.z = pcbIUScale.IUTomm( ScaleSize( Convert( arr[8] ) ) );
247 }
248
249 if( !modelTitle.IsEmpty() && footprint->Models().empty() )
250 {
251 FP_3DMODEL model;
252 model.m_Filename = kicadModelPrefix
253 + EscapeString( modelTitle, ESCAPE_CONTEXT::CTX_FILENAME )
254 + wxS( ".step" );
255 model.m_Offset = kmodelOffset;
256 model.m_Rotation = kmodelRotation;
257 footprint->Models().push_back( model );
258 }
259}
260
261
262std::vector<std::unique_ptr<PCB_SHAPE>>
263PCB_IO_EASYEDAPRO_PARSER::ParsePoly( BOARD_ITEM_CONTAINER* aContainer, nlohmann::json polyData,
264 bool aClosed, bool aInFill ) const
265{
266 std::vector<std::unique_ptr<PCB_SHAPE>> results;
267
268 VECTOR2D prevPt;
269 for( int i = 0; i < polyData.size(); i++ )
270 {
271 nlohmann::json val = polyData.at( i );
272
273 if( val.is_string() )
274 {
275 wxString str = val;
276 if( str == wxS( "CIRCLE" ) )
277 {
279 center.x = ( polyData.at( ++i ) );
280 center.y = ( polyData.at( ++i ) );
281 double r = ( polyData.at( ++i ) );
282
283 std::unique_ptr<PCB_SHAPE> shape =
284 std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::CIRCLE );
285
286 shape->SetCenter( ScalePos( center ) );
287 shape->SetEnd( ScalePos( center + VECTOR2D( r, 0 ) ) );
288 shape->SetFilled( aClosed );
289
290 results.emplace_back( std::move( shape ) );
291 }
292 else if( str == wxS( "R" ) )
293 {
294 VECTOR2D start, size;
295 start.x = ( polyData.at( ++i ) );
296 start.y = ( polyData.at( ++i ) );
297 size.x = ( polyData.at( ++i ) );
298 size.y = -( polyData.at( ++i ).get<double>() );
299 double angle = polyData.at( ++i );
300 double cr = ( i + 1 ) < polyData.size() ? polyData.at( ++i ).get<double>() : 0;
301
302 if( cr == 0 )
303 {
304 std::unique_ptr<PCB_SHAPE> shape =
305 std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::RECTANGLE );
306
307 shape->SetStart( ScalePos( start ) );
308 shape->SetEnd( ScalePos( start + size ) );
309 shape->SetFilled( aClosed );
310 shape->Rotate( ScalePos( start ), EDA_ANGLE( angle, DEGREES_T ) );
311
312 results.emplace_back( std::move( shape ) );
313 }
314 else
315 {
316 VECTOR2D end = start + size;
317
318 auto addSegment = [&]( VECTOR2D aStart, VECTOR2D aEnd )
319 {
320 std::unique_ptr<PCB_SHAPE> shape =
321 std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::SEGMENT );
322
323 shape->SetStart( ScalePos( aStart ) );
324 shape->SetEnd( ScalePos( aEnd ) );
325 shape->SetFilled( aClosed );
326 shape->Rotate( ScalePos( start ), EDA_ANGLE( angle, DEGREES_T ) );
327
328 results.emplace_back( std::move( shape ) );
329 };
330
331 auto addArc = [&]( VECTOR2D aStart, VECTOR2D aEnd, VECTOR2D center )
332 {
333 std::unique_ptr<PCB_SHAPE> shape =
334 std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::ARC );
335
336 shape->SetStart( ScalePos( aStart ) );
337 shape->SetEnd( ScalePos( aEnd ) );
338 shape->SetCenter( ScalePos( center ) );
339 shape->SetFilled( aClosed );
340 shape->Rotate( ScalePos( start ), EDA_ANGLE( angle, DEGREES_T ) );
341
342 results.emplace_back( std::move( shape ) );
343 };
344
345 addSegment( { start.x + cr, start.y }, { end.x - cr, start.y } );
346 addSegment( { end.x, start.y - cr }, { end.x, end.y + cr } );
347 addSegment( { start.x + cr, end.y }, { end.x - cr, end.y } );
348 addSegment( { start.x, start.y - cr }, { start.x, end.y + cr } );
349
350 addArc( { end.x - cr, start.y }, { end.x, start.y - cr },
351 { end.x - cr, start.y - cr } );
352
353 addArc( { end.x, end.y + cr }, { end.x - cr, end.y },
354 { end.x - cr, end.y + cr } );
355
356 addArc( { start.x + cr, end.y }, { start.x, end.y + cr },
357 { start.x + cr, end.y + cr } );
358
359 addArc( { start.x, start.y - cr }, { start.x + cr, start.y },
360 { start.x + cr, start.y - cr } );
361 }
362 }
363 else if( str == wxS( "ARC" ) || str == wxS( "CARC" ) )
364 {
366 double angle = polyData.at( ++i ).get<double>() / ( aInFill ? 10 : 1 );
367 end.x = ( polyData.at( ++i ) );
368 end.y = ( polyData.at( ++i ) );
369
370 std::unique_ptr<PCB_SHAPE> shape =
371 std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::ARC );
372
373 if( angle < 0 )
374 {
375 shape->SetStart( ScalePos( prevPt ) );
376 shape->SetEnd( ScalePos( end ) );
377 }
378 else
379 {
380 shape->SetStart( ScalePos( end ) );
381 shape->SetEnd( ScalePos( prevPt ) );
382 }
383
384 VECTOR2D delta = end - prevPt;
385 VECTOR2D mid = ( prevPt + delta / 2 );
386
387 double ha = angle / 2;
388 double hd = delta.EuclideanNorm() / 2;
389 double cdist = hd / tan( DEG2RAD( ha ) );
390 VECTOR2D center = mid + delta.Perpendicular().Resize( cdist );
391 shape->SetCenter( ScalePos( center ) );
392
393 shape->SetFilled( aClosed );
394
395 results.emplace_back( std::move( shape ) );
396
397 prevPt = end;
398 }
399 else if( str == wxS( "L" ) )
400 {
402 chain.Append( ScalePos( prevPt ) );
403
404 while( i < polyData.size() - 2 && polyData.at( i + 1 ).is_number() )
405 {
406 VECTOR2D pt;
407 pt.x = ( polyData.at( ++i ) );
408 pt.y = ( polyData.at( ++i ) );
409
410 chain.Append( ScalePos( pt ) );
411
412 prevPt = pt;
413 }
414
415 if( aClosed )
416 {
417 std::unique_ptr<PCB_SHAPE> shape =
418 std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::POLY );
419
420 wxASSERT( chain.PointCount() > 2 );
421
422 if( chain.PointCount() > 2 )
423 {
424 chain.SetClosed( true );
425 shape->SetFilled( true );
426 shape->SetPolyShape( chain );
427
428 results.emplace_back( std::move( shape ) );
429 }
430 }
431 else
432 {
433 for( int s = 0; s < chain.SegmentCount(); s++ )
434 {
435 SEG seg = chain.Segment( s );
436
437 std::unique_ptr<PCB_SHAPE> shape =
438 std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::SEGMENT );
439
440 shape->SetStart( seg.A );
441 shape->SetEnd( seg.B );
442
443 results.emplace_back( std::move( shape ) );
444 }
445 }
446 }
447 }
448 else if( val.is_number() )
449 {
450 prevPt.x = ( polyData.at( i ) );
451 prevPt.y = ( polyData.at( ++i ) );
452 }
453 }
454
455 return results;
456}
457
458
460PCB_IO_EASYEDAPRO_PARSER::ParseContour( nlohmann::json polyData, bool aInFill,
461 double aArcAccuracy ) const
462{
463 SHAPE_LINE_CHAIN result;
464 VECTOR2D prevPt;
465
466 for( int i = 0; i < polyData.size(); i++ )
467 {
468 nlohmann::json val = polyData.at( i );
469
470 if( val.is_string() )
471 {
472 wxString str = val;
473 if( str == wxS( "CIRCLE" ) )
474 {
476 center.x = ( polyData.at( ++i ) );
477 center.y = ( polyData.at( ++i ) );
478 double r = ( polyData.at( ++i ) );
479
481 ERROR_INSIDE );
482 }
483 else if( str == wxS( "R" ) )
484 {
485 VECTOR2D start, size;
486 start.x = ( polyData.at( ++i ) );
487 start.y = ( polyData.at( ++i ) );
488 size.x = ( polyData.at( ++i ) );
489 size.y = ( polyData.at( ++i ).get<double>() );
490 double angle = polyData.at( ++i );
491 double cr = ( i + 1 ) < polyData.size() ? polyData.at( ++i ).get<double>() : 0;
492
493 SHAPE_POLY_SET poly;
494
495 VECTOR2D kstart = ScalePos( start );
496 VECTOR2D ksize = ScaleSize( size );
497 VECTOR2D kcenter = kstart + ksize / 2;
498 RotatePoint( kcenter, kstart, EDA_ANGLE( angle, DEGREES_T ) );
499
501 poly, kcenter, ksize, EDA_ANGLE( angle, DEGREES_T ), ScaleSize( cr ), 0, 0,
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, aArcAccuracy );
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, aArcAccuracy );
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().Flip() );
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 {
676 pad->SetShape( PADSTACK::ALL_LAYERS, PAD_SHAPE::RECTANGLE );
677 }
678 else
679 {
680 pad->SetShape( PADSTACK::ALL_LAYERS, PAD_SHAPE::ROUNDRECT );
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 ) );
691 pad->SetShape( PADSTACK::ALL_LAYERS, PAD_SHAPE::CIRCLE );
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 ) );
700 pad->SetShape( PADSTACK::ALL_LAYERS, PAD_SHAPE::OVAL );
701 }
702 else if( padSh == wxS( "POLY" ) )
703 {
704 pad->SetShape( PADSTACK::ALL_LAYERS, PAD_SHAPE::CUSTOM );
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( REFERENCE_FIELD )->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->SetDoNotAllowCopperPour( !!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*> shapes;
932 std::vector<std::unique_ptr<PCB_SHAPE>> newShapes;
933
934 for( BOARD_ITEM* item : footprint->GraphicalItems() )
935 {
936 if( !item->IsOnLayer( Edge_Cuts ) )
937 continue;
938
939 if( item->Type() == PCB_SHAPE_T )
940 shapes.push_back( static_cast<PCB_SHAPE*>( item ) );
941 }
942
943 ConnectBoardShapes( shapes, newShapes, SHAPE_JOIN_DISTANCE );
944
945 for( std::unique_ptr<PCB_SHAPE>& ptr : newShapes )
946 footprint->Add( ptr.release(), ADD_MODE::APPEND );
947
948 return footprintPtr.release();
949}
950
951
953 BOARD* aBoard, const nlohmann::json& aProject,
954 std::map<wxString, std::unique_ptr<FOOTPRINT>>& aFootprintMap,
955 const std::map<wxString, EASYEDAPRO::BLOB>& aBlobMap,
956 const std::multimap<wxString, EASYEDAPRO::POURED>& aPouredMap,
957 const std::vector<nlohmann::json>& aLines, const wxString& aFpLibName )
958{
959 std::map<wxString, std::vector<nlohmann::json>> componentLines;
960 std::map<wxString, std::vector<nlohmann::json>> ruleLines;
961
962 std::multimap<wxString, EASYEDAPRO::POURED> boardPouredMap = aPouredMap;
963 std::map<wxString, ZONE*> poursToFill;
964
966
967 for( const nlohmann::json& line : aLines )
968 {
969 if( line.size() == 0 )
970 continue;
971
972 wxString type = line.at( 0 );
973
974 if( type == wxS( "LAYER" ) )
975 {
976 int layer = line.at( 1 );
977 PCB_LAYER_ID klayer = LayerToKi( layer );
978
979 wxString layerType = line.at( 2 );
980 wxString layerName = line.at( 3 );
981 int layerFlag = line.at( 4 );
982
983 if( layerFlag != 0 )
984 {
985 LSET blayers = aBoard->GetEnabledLayers();
986 blayers.set( klayer );
987 aBoard->SetEnabledLayers( blayers );
988 aBoard->SetLayerName( klayer, layerName );
989 }
990 }
991 else if( type == wxS( "NET" ) )
992 {
993 wxString netname = line.at( 1 );
994
995 aBoard->Add( new NETINFO_ITEM( aBoard, netname, aBoard->GetNetCount() + 1 ),
996 ADD_MODE::APPEND );
997 }
998 else if( type == wxS( "RULE" ) )
999 {
1000 wxString ruleType = line.at( 1 );
1001 wxString ruleName = line.at( 2 );
1002 int isDefault = line.at( 3 );
1003 nlohmann::json ruleData = line.at( 4 );
1004
1005 if( ruleType == wxS( "3" ) && isDefault ) // Track width
1006 {
1007 wxString units = ruleData.at( 0 );
1008 double minVal = ruleData.at( 1 );
1009 double optVal = ruleData.at( 2 );
1010 double maxVal = ruleData.at( 3 );
1011
1012 bds.m_TrackMinWidth = ScaleSize( minVal );
1013 }
1014 else if( ruleType == wxS( "1" ) && isDefault )
1015 {
1016 wxString units = ruleData.at( 0 );
1017 nlohmann::json table = ruleData.at( 1 );
1018
1019 int minVal = INT_MAX;
1020 for( const std::vector<int>& arr : table )
1021 {
1022 for( int val : arr )
1023 {
1024 if( val < minVal )
1025 minVal = val;
1026 }
1027 }
1028
1029 bds.m_MinClearance = ScaleSize( minVal );
1030 }
1031
1032 ruleLines[ruleType].push_back( line );
1033 }
1034 else if( type == wxS( "POURED" ) )
1035 {
1036 if( !line.at( 2 ).is_string() )
1037 continue; // Unknown type of POURED
1038
1039 EASYEDAPRO::POURED poured = line;
1040 boardPouredMap.emplace( poured.parentId, poured );
1041 }
1042 else if( type == wxS( "VIA" ) || type == wxS( "LINE" ) || type == wxS( "ARC" )
1043 || type == wxS( "POLY" ) || type == wxS( "FILL" ) || type == wxS( "POUR" ) )
1044 {
1045 wxString uuid = line.at( 1 );
1046
1047 // if( line.at( 2 ).is_number() )
1048 // int unk = line.at( 2 ).get<int>();
1049 // else if( line.at( 2 ).is_string() )
1050 // int unk = wxAtoi( line.at( 2 ).get<wxString>() );
1051
1052 wxString netname = line.at( 3 );
1053
1054 if( type == wxS( "VIA" ) )
1055 {
1057 center.x = line.at( 5 );
1058 center.y = line.at( 6 );
1059
1060 double drill = line.at( 7 );
1061 double dia = line.at( 8 );
1062
1063 std::unique_ptr<PCB_VIA> via = std::make_unique<PCB_VIA>( aBoard );
1064
1065 via->SetPosition( ScalePos( center ) );
1066 via->SetDrill( ScaleSize( drill ) );
1067 via->SetWidth( PADSTACK::ALL_LAYERS, ScaleSize( dia ) );
1068
1069 via->SetNet( aBoard->FindNet( netname ) );
1070
1071 aBoard->Add( via.release(), ADD_MODE::APPEND );
1072 }
1073 else if( type == wxS( "LINE" ) )
1074 {
1075 int layer = line.at( 4 ).get<int>();
1076 PCB_LAYER_ID klayer = LayerToKi( layer );
1077
1078 VECTOR2D start;
1079 start.x = line.at( 5 );
1080 start.y = line.at( 6 );
1081
1082 VECTOR2D end;
1083 end.x = line.at( 7 );
1084 end.y = line.at( 8 );
1085
1086 double width = line.at( 9 );
1087
1088 std::unique_ptr<PCB_TRACK> track = std::make_unique<PCB_TRACK>( aBoard );
1089
1090 track->SetLayer( klayer );
1091 track->SetStart( ScalePos( start ) );
1092 track->SetEnd( ScalePos( end ) );
1093 track->SetWidth( ScaleSize( width ) );
1094
1095 track->SetNet( aBoard->FindNet( netname ) );
1096
1097 aBoard->Add( track.release(), ADD_MODE::APPEND );
1098 }
1099 else if( type == wxS( "ARC" ) )
1100 {
1101 int layer = line.at( 4 ).get<int>();
1102 PCB_LAYER_ID klayer = LayerToKi( layer );
1103
1104 VECTOR2D start;
1105 start.x = line.at( 5 );
1106 start.y = line.at( 6 );
1107
1108 VECTOR2D end;
1109 end.x = line.at( 7 );
1110 end.y = line.at( 8 );
1111
1112 double angle = line.at( 9 );
1113 double width = line.at( 10 );
1114
1115 VECTOR2D delta = end - start;
1116 VECTOR2D mid = ( start + delta / 2 );
1117
1118 double ha = angle / 2;
1119 double hd = delta.EuclideanNorm() / 2;
1120 double cdist = hd / tan( DEG2RAD( ha ) );
1121 VECTOR2D center = mid + delta.Perpendicular().Resize( cdist );
1122
1123 SHAPE_ARC sarc;
1125 ScalePos( center ), angle >= 0, width );
1126
1127 std::unique_ptr<PCB_ARC> arc = std::make_unique<PCB_ARC>( aBoard, &sarc );
1128 arc->SetWidth( ScaleSize( width ) );
1129
1130 arc->SetLayer( klayer );
1131 arc->SetNet( aBoard->FindNet( netname ) );
1132
1133 aBoard->Add( arc.release(), ADD_MODE::APPEND );
1134 }
1135 else if( type == wxS( "FILL" ) )
1136 {
1137 int layer = line.at( 4 ).get<int>();
1138 PCB_LAYER_ID klayer = LayerToKi( layer );
1139
1140 double width = line.at( 5 );
1141
1142 nlohmann::json polyDataList = line.at( 7 );
1143
1144 if( !polyDataList.at( 0 ).is_array() )
1145 polyDataList = nlohmann::json::array( { polyDataList } );
1146
1147 std::vector<SHAPE_LINE_CHAIN> contours;
1148 for( nlohmann::json& polyData : polyDataList )
1149 {
1150 SHAPE_LINE_CHAIN contour = ParseContour( polyData, true );
1151 contour.SetClosed( true );
1152
1153 contours.push_back( contour );
1154 }
1155
1156 SHAPE_POLY_SET zoneFillPoly;
1157
1158 for( SHAPE_LINE_CHAIN& contour : contours )
1159 zoneFillPoly.AddOutline( contour );
1160
1161 zoneFillPoly.RebuildHolesFromContours();
1162 zoneFillPoly.Fracture();
1163
1164 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>( aBoard );
1165
1166 zone->SetNet( aBoard->FindNet( netname ) );
1167 zone->SetLayer( klayer );
1168 zone->Outline()->Append( SHAPE_RECT( zoneFillPoly.BBox() ).Outline() );
1169 zone->SetFilledPolysList( klayer, zoneFillPoly );
1170 zone->SetAssignedPriority( 500 );
1171 zone->SetIsFilled( true );
1172 zone->SetNeedRefill( false );
1173
1174 zone->SetLocalClearance( bds.m_MinClearance );
1175 zone->SetMinThickness( bds.m_TrackMinWidth );
1176
1177 aBoard->Add( zone.release(), ADD_MODE::APPEND );
1178 }
1179 else if( type == wxS( "POLY" ) )
1180 {
1181 int layer = line.at( 4 );
1182 PCB_LAYER_ID klayer = LayerToKi( layer );
1183
1184 double thickness = line.at( 5 );
1185 nlohmann::json polyData = line.at( 6 );
1186
1187 std::vector<std::unique_ptr<PCB_SHAPE>> results =
1188 ParsePoly( aBoard, polyData, false, false );
1189
1190 for( auto& shape : results )
1191 {
1192 shape->SetLayer( klayer );
1193 shape->SetWidth( ScaleSize( thickness ) );
1194
1195 aBoard->Add( shape.release(), ADD_MODE::APPEND );
1196 }
1197 }
1198 else if( type == wxS( "POUR" ) )
1199 {
1200 int layer = line.at( 4 ).get<int>();
1201 PCB_LAYER_ID klayer = LayerToKi( layer );
1202
1203 double lineWidth = line.at( 5 ); // Doesn't matter
1204 wxString pourname = line.at( 6 );
1205 int fillOrder = line.at( 7 ).get<int>();
1206 nlohmann::json polyDataList = line.at( 8 );
1207
1208 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>( aBoard );
1209
1210 zone->SetNet( aBoard->FindNet( netname ) );
1211 zone->SetLayer( klayer );
1212 zone->SetAssignedPriority( 500 - fillOrder );
1213 zone->SetLocalClearance( bds.m_MinClearance );
1214 zone->SetMinThickness( bds.m_TrackMinWidth );
1215
1216 for( nlohmann::json& polyData : polyDataList )
1217 {
1218 SHAPE_LINE_CHAIN contour = ParseContour( polyData, false );
1219 contour.SetClosed( true );
1220
1221 zone->Outline()->Append( contour );
1222 }
1223
1224 wxASSERT( zone->Outline()->OutlineCount() == 1 );
1225
1226 poursToFill.emplace( uuid, zone.get() );
1227
1228 aBoard->Add( zone.release(), ADD_MODE::APPEND );
1229 }
1230 }
1231 else if( type == wxS( "TEARDROP" ) )
1232 {
1233 wxString uuid = line.at( 1 );
1234 wxString netname = line.at( 2 );
1235 int layer = line.at( 3 ).get<int>();
1236 PCB_LAYER_ID klayer = LayerToKi( layer );
1237
1238 nlohmann::json polyData = line.at( 4 );
1239
1240 SHAPE_LINE_CHAIN contour = ParseContour( polyData, false );
1241 contour.SetClosed( true );
1242
1243 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>( aBoard );
1244
1245 zone->SetNet( aBoard->FindNet( netname ) );
1246 zone->SetLayer( klayer );
1247 zone->Outline()->Append( contour );
1248 zone->SetFilledPolysList( klayer, contour );
1249 zone->SetNeedRefill( false );
1250 zone->SetIsFilled( true );
1251
1252 zone->SetAssignedPriority( 600 );
1253 zone->SetLocalClearance( 0 );
1254 zone->SetMinThickness( 0 );
1255 zone->SetTeardropAreaType( TEARDROP_TYPE::TD_UNSPECIFIED );
1256
1257 aBoard->Add( zone.release(), ADD_MODE::APPEND );
1258 }
1259 else if( type == wxS( "REGION" ) )
1260 {
1261 wxString uuid = line.at( 1 );
1262
1263 // if( line.at( 2 ).is_number() )
1264 // int unk = line.at( 2 ).get<int>();
1265 // else if( line.at( 2 ).is_string() )
1266 // int unk = wxAtoi( line.at( 2 ).get<wxString>() );
1267
1268 int layer = line.at( 3 ).get<int>();
1269 PCB_LAYER_ID klayer = LayerToKi( layer );
1270
1271 double width = line.at( 4 );
1272 std::set<int> flags = line.at( 5 );
1273 nlohmann::json polyDataList = line.at( 6 );
1274
1275 for( nlohmann::json& polyData : polyDataList )
1276 {
1277 SHAPE_LINE_CHAIN contour = ParseContour( polyData, false );
1278 contour.SetClosed( true );
1279
1280 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>( aBoard );
1281
1282 zone->SetIsRuleArea( true );
1283 zone->SetDoNotAllowFootprints( !!flags.count( 2 ) );
1284 zone->SetDoNotAllowCopperPour( !!flags.count( 7 ) || !!flags.count( 6 )
1285 || !!flags.count( 8 ) );
1286 zone->SetDoNotAllowPads( !!flags.count( 7 ) );
1287 zone->SetDoNotAllowTracks( !!flags.count( 7 ) || !!flags.count( 5 ) );
1288 zone->SetDoNotAllowVias( !!flags.count( 7 ) );
1289
1290 zone->SetLayer( klayer );
1291 zone->Outline()->Append( contour );
1292
1293 aBoard->Add( zone.release(), ADD_MODE::APPEND );
1294 }
1295 }
1296 else if( type == wxS( "PAD" ) )
1297 {
1298 wxString netname = line.at( 3 );
1299
1300 std::unique_ptr<FOOTPRINT> footprint = std::make_unique<FOOTPRINT>( aBoard );
1301 std::unique_ptr<PAD> pad = createPAD( footprint.get(), line );
1302
1303 pad->SetNet( aBoard->FindNet( netname ) );
1304
1305 VECTOR2I pos = pad->GetPosition();
1306 EDA_ANGLE orient = pad->GetOrientation();
1307
1308 pad->SetPosition( VECTOR2I() );
1309 pad->SetOrientation( ANGLE_0 );
1310
1311 footprint->Add( pad.release(), ADD_MODE::APPEND );
1312 footprint->SetPosition( pos );
1313 footprint->SetOrientation( orient );
1314
1315 wxString fpName = wxS( "Pad_" ) + line.at( 1 ).get<wxString>();
1316 LIB_ID fpID = EASYEDAPRO::ToKiCadLibID( wxEmptyString, fpName );
1317
1318 footprint->SetFPID( fpID );
1319 footprint->Reference().SetVisible( true );
1320 footprint->Value().SetVisible( true );
1321 footprint->AutoPositionFields();
1322
1323 aBoard->Add( footprint.release(), ADD_MODE::APPEND );
1324 }
1325 else if( type == wxS( "IMAGE" ) )
1326 {
1327 wxString uuid = line.at( 1 );
1328
1329 // if( line.at( 2 ).is_number() )
1330 // int unk = line.at( 2 ).get<int>();
1331 // else if( line.at( 2 ).is_string() )
1332 // int unk = wxAtoi( line.at( 2 ).get<wxString>() );
1333
1334 int layer = line.at( 3 ).get<int>();
1335 PCB_LAYER_ID klayer = LayerToKi( layer );
1336
1337 VECTOR2D start( line.at( 4 ), line.at( 5 ) );
1338 VECTOR2D size( line.at( 6 ), line.at( 7 ) );
1339
1340 double angle = line.at( 8 ); // from top left corner
1341 int mirror = line.at( 9 );
1342 nlohmann::json polyDataList = line.at( 10 );
1343
1344 BOX2I bbox;
1345 std::vector<SHAPE_LINE_CHAIN> contours;
1346 for( nlohmann::json& polyData : polyDataList )
1347 {
1348 SHAPE_LINE_CHAIN contour = ParseContour( polyData, false );
1349 contour.SetClosed( true );
1350
1351 contours.push_back( contour );
1352
1353 bbox.Merge( contour.BBox() );
1354 }
1355
1356 VECTOR2D scale( ScaleSize( size.x ) / bbox.GetSize().x,
1357 ScaleSize( size.y ) / bbox.GetSize().y );
1358
1359 SHAPE_POLY_SET polySet;
1360
1361 for( SHAPE_LINE_CHAIN& contour : contours )
1362 {
1363 for( int i = 0; i < contour.PointCount(); i++ )
1364 {
1365 VECTOR2I pt = contour.CPoint( i );
1366 contour.SetPoint( i, VECTOR2I( pt.x * scale.x, pt.y * scale.y ) );
1367 }
1368
1369 polySet.AddOutline( contour );
1370 }
1371
1372 polySet.RebuildHolesFromContours();
1373
1374 std::unique_ptr<PCB_GROUP> group;
1375
1376 if( polySet.OutlineCount() > 1 )
1377 group = std::make_unique<PCB_GROUP>( aBoard );
1378
1379 BOX2I polyBBox = polySet.BBox();
1380
1381 for( const SHAPE_POLY_SET::POLYGON& poly : polySet.CPolygons() )
1382 {
1383 std::unique_ptr<PCB_SHAPE> shape =
1384 std::make_unique<PCB_SHAPE>( aBoard, SHAPE_T::POLY );
1385
1386 shape->SetFilled( true );
1387 shape->SetPolyShape( poly );
1388 shape->SetLayer( klayer );
1389 shape->SetWidth( 0 );
1390
1391 shape->Move( ScalePos( start ) - polyBBox.GetOrigin() );
1392 shape->Rotate( ScalePos( start ), EDA_ANGLE( angle, DEGREES_T ) );
1393
1394 if( IsBackLayer( klayer ) ^ !!mirror )
1395 {
1396 FLIP_DIRECTION flipDirection = IsBackLayer( klayer )
1397 ? FLIP_DIRECTION::TOP_BOTTOM
1398 : FLIP_DIRECTION::LEFT_RIGHT;
1399 shape->Mirror( ScalePos( start ), flipDirection );
1400 }
1401
1402 if( group )
1403 group->AddItem( shape.get() );
1404
1405 aBoard->Add( shape.release(), ADD_MODE::APPEND );
1406 }
1407
1408 if( group )
1409 aBoard->Add( group.release(), ADD_MODE::APPEND );
1410 }
1411 else if( type == wxS( "OBJ" ) )
1412 {
1413 VECTOR2D start, size;
1414 wxString mimeType, base64Data;
1415 double angle = 0;
1416 int flipped = 0;
1417
1418 if( !line.at( 3 ).is_number() )
1419 continue;
1420
1421 int layer = line.at( 3 ).get<int>();
1422 PCB_LAYER_ID klayer = LayerToKi( layer );
1423
1424 start = VECTOR2D( line.at( 5 ), line.at( 6 ) );
1425 size = VECTOR2D( line.at( 7 ), line.at( 8 ) );
1426 angle = line.at( 9 );
1427 flipped = line.at( 10 );
1428
1429 wxString imageUrl = line.at( 11 );
1430
1431 if( imageUrl.BeforeFirst( ':' ) == wxS( "blob" ) )
1432 {
1433 wxString objectId = imageUrl.AfterLast( ':' );
1434
1435 if( auto blob = get_opt( aBlobMap, objectId ) )
1436 {
1437 wxString blobUrl = blob->url;
1438
1439 if( blobUrl.BeforeFirst( ':' ) == wxS( "data" ) )
1440 {
1441 wxArrayString paramsArr =
1442 wxSplit( blobUrl.AfterFirst( ':' ).BeforeFirst( ',' ), ';', '\0' );
1443
1444 base64Data = blobUrl.AfterFirst( ',' );
1445
1446 if( paramsArr.size() > 0 )
1447 mimeType = paramsArr[0];
1448 }
1449 }
1450 }
1451
1452 VECTOR2D kstart = ScalePos( start );
1453 VECTOR2D ksize = ScaleSize( size );
1454
1455 if( mimeType.empty() || base64Data.empty() )
1456 continue;
1457
1458 wxMemoryBuffer buf = wxBase64Decode( base64Data );
1459
1460 if( mimeType == wxS( "image/svg+xml" ) )
1461 {
1462 // Not yet supported by EasyEDA
1463 }
1464 else
1465 {
1466 VECTOR2D kcenter = kstart + ksize / 2;
1467
1468 std::unique_ptr<PCB_REFERENCE_IMAGE> bitmap =
1469 std::make_unique<PCB_REFERENCE_IMAGE>( aBoard, kcenter, klayer );
1470 REFERENCE_IMAGE& refImage = bitmap->GetReferenceImage();
1471
1472 wxImage::SetDefaultLoadFlags( wxImage::GetDefaultLoadFlags()
1473 & ~wxImage::Load_Verbose );
1474
1475 if( refImage.ReadImageFile( buf ) )
1476 {
1477 double scaleFactor = ScaleSize( size.x ) / refImage.GetSize().x;
1478 refImage.SetImageScale( scaleFactor );
1479
1480 // TODO: support non-90-deg angles
1481 bitmap->Rotate( kstart, EDA_ANGLE( angle, DEGREES_T ) );
1482
1483 if( flipped )
1484 {
1485 int x = bitmap->GetPosition().x;
1486 MIRROR( x, KiROUND( kstart.x ) );
1487 bitmap->SetX( x );
1488
1489 refImage.MutableImage().Mirror( FLIP_DIRECTION::LEFT_RIGHT );
1490 }
1491
1492 aBoard->Add( bitmap.release(), ADD_MODE::APPEND );
1493 }
1494 }
1495 }
1496 else if( type == wxS( "STRING" ) )
1497 {
1498 wxString uuid = line.at( 1 );
1499
1500 // if( line.at( 2 ).is_number() )
1501 // int unk = line.at( 2 ).get<int>();
1502 // else if( line.at( 2 ).is_string() )
1503 // int unk = wxAtoi( line.at( 2 ).get<wxString>() );
1504
1505 int layer = line.at( 3 ).get<int>();
1506 PCB_LAYER_ID klayer = LayerToKi( layer );
1507
1508 VECTOR2D location( line.at( 4 ), line.at( 5 ) );
1509 wxString string = line.at( 6 );
1510 wxString font = line.at( 7 );
1511
1512 double height = line.at( 8 );
1513 double strokew = line.at( 9 );
1514
1515 int align = line.at( 12 );
1516 double angle = line.at( 13 );
1517 int inverted = line.at( 14 );
1518 int mirror = line.at( 16 );
1519
1520 PCB_TEXT* text = new PCB_TEXT( aBoard );
1521
1522 text->SetText( string );
1523 text->SetLayer( klayer );
1524 text->SetPosition( ScalePos( location ) );
1525 text->SetIsKnockout( inverted );
1526 text->SetTextThickness( ScaleSize( strokew ) );
1527 text->SetTextSize( VECTOR2D( ScaleSize( height * 0.6 ), ScaleSize( height * 0.7 ) ) );
1528
1529 if( font != wxS( "default" ) )
1530 {
1531 text->SetFont( KIFONT::FONT::GetFont( font ) );
1532 //text->SetupRenderCache( text->GetShownText(), text->GetFont(), EDA_ANGLE( angle, DEGREES_T ) );
1533
1534 //text->AddRenderCacheGlyph();
1535 // TODO: import geometry cache
1536 }
1537
1538 AlignText( text, align );
1539
1540 if( IsBackLayer( klayer ) ^ !!mirror )
1541 {
1542 text->SetMirrored( true );
1543 text->SetTextAngleDegrees( -angle );
1544 }
1545 else
1546 {
1547 text->SetTextAngleDegrees( angle );
1548 }
1549
1550 aBoard->Add( text, ADD_MODE::APPEND );
1551 }
1552 else if( type == wxS( "COMPONENT" ) )
1553 {
1554 wxString compId = line.at( 1 );
1555 componentLines[compId].push_back( line );
1556 }
1557 else if( type == wxS( "ATTR" ) )
1558 {
1559 wxString compId = line.at( 3 );
1560 componentLines[compId].push_back( line );
1561 }
1562 else if( type == wxS( "PAD_NET" ) )
1563 {
1564 wxString compId = line.at( 1 );
1565 componentLines[compId].push_back( line );
1566 }
1567 }
1568
1569 for( auto const& [compId, lines] : componentLines )
1570 {
1571 wxString deviceId;
1572 wxString fpIdOverride;
1573 wxString fpDesignator;
1574 std::map<wxString, wxString> localCompAttribs;
1575
1576 for( auto& line : lines )
1577 {
1578 if( line.size() == 0 )
1579 continue;
1580
1581 wxString type = line.at( 0 );
1582
1583 if( type == wxS( "COMPONENT" ) )
1584 {
1585 localCompAttribs = line.at( 7 );
1586 }
1587 else if( type == wxS( "ATTR" ) )
1588 {
1589 EASYEDAPRO::PCB_ATTR attr = line;
1590
1591 if( attr.key == wxS( "Device" ) )
1592 deviceId = attr.value;
1593
1594 else if( attr.key == wxS( "Footprint" ) )
1595 fpIdOverride = attr.value;
1596
1597 else if( attr.key == wxS( "Designator" ) )
1598 fpDesignator = attr.value;
1599 }
1600 }
1601
1602 if( deviceId.empty() )
1603 continue;
1604
1605 nlohmann::json compAttrs = aProject.at( "devices" ).at( deviceId ).at( "attributes" );
1606
1607 wxString fpId;
1608
1609 if( !fpIdOverride.IsEmpty() )
1610 fpId = fpIdOverride;
1611 else
1612 fpId = compAttrs.at( "Footprint" ).get<wxString>();
1613
1614 auto it = aFootprintMap.find( fpId );
1615 if( it == aFootprintMap.end() )
1616 {
1617 wxLogError( "Footprint of '%s' with uuid '%s' not found.", fpDesignator, fpId );
1618 continue;
1619 }
1620
1621 std::unique_ptr<FOOTPRINT>& footprintOrig = it->second;
1622 std::unique_ptr<FOOTPRINT> footprint( static_cast<FOOTPRINT*>( footprintOrig->Clone() ) );
1623
1624 wxString modelUuid, modelTitle, modelTransform;
1625
1626 if( auto val = get_opt( localCompAttribs, "3D Model" ) )
1627 modelUuid = *val;
1628 else
1629 modelUuid = compAttrs.value<wxString>( "3D Model", "" );
1630
1631 if( auto val = get_opt( localCompAttribs, "3D Model Title" ) )
1632 modelTitle = val->Trim();
1633 else
1634 modelTitle = compAttrs.value<wxString>( "3D Model Title", modelUuid ).Trim();
1635
1636 if( auto val = get_opt( localCompAttribs, "3D Model Transform" ) )
1637 modelTransform = *val;
1638 else
1639 modelTransform = compAttrs.value<wxString>( "3D Model Transform", "" );
1640
1641 fillFootprintModelInfo( footprint.get(), modelUuid, modelTitle, modelTransform );
1642
1643 footprint->SetParent( aBoard );
1644
1645 for( auto& line : lines )
1646 {
1647 if( line.size() == 0 )
1648 continue;
1649
1650 wxString type = line.at( 0 );
1651
1652 if( type == wxS( "COMPONENT" ) )
1653 {
1654 int layer = line.at( 3 );
1655 PCB_LAYER_ID klayer = LayerToKi( layer );
1656
1657 VECTOR2D center( line.at( 4 ), line.at( 5 ) );
1658
1659 double orient = line.at( 6 );
1660 //std::map<wxString, wxString> props = line.at( 7 );
1661
1662 if( klayer == B_Cu )
1663 footprint->Flip( footprint->GetPosition(), FLIP_DIRECTION::TOP_BOTTOM );
1664
1665 footprint->SetOrientationDegrees( orient );
1666 footprint->SetPosition( ScalePos( center ) );
1667 }
1668 else if( type == wxS( "ATTR" ) )
1669 {
1670 EASYEDAPRO::PCB_ATTR attr = line;
1671
1672 PCB_LAYER_ID klayer = LayerToKi( attr.layer );
1673
1674 PCB_FIELD* field = nullptr;
1675 bool add = false;
1676
1677 if( attr.key == wxS( "Designator" ) )
1678 {
1679 if( attr.key == wxS( "Designator" ) )
1680 {
1681 field = footprint->GetField( REFERENCE_FIELD );
1682 }
1683 else
1684 {
1685 field = new PCB_FIELD( footprint.get(), -1, attr.key );
1686 add = true;
1687 }
1688
1689 if( attr.fontName != wxS( "default" ) )
1690 field->SetFont( KIFONT::FONT::GetFont( attr.fontName ) );
1691
1692 if( attr.valVisible && attr.keyVisible )
1693 {
1694 field->SetText( attr.key + ':' + attr.value );
1695 }
1696 else if( attr.keyVisible )
1697 {
1698 field->SetText( attr.key );
1699 }
1700 else
1701 {
1702 field->SetVisible( false );
1703 field->SetText( attr.value );
1704 }
1705
1706 field->SetLayer( klayer );
1707 field->SetPosition( ScalePos( attr.position ) );
1708 field->SetTextAngleDegrees( footprint->IsFlipped() ? -attr.rotation
1709 : attr.rotation );
1710 field->SetIsKnockout( attr.inverted );
1711 field->SetTextThickness( ScaleSize( attr.strokeWidth ) );
1712 field->SetTextSize( VECTOR2D( ScaleSize( attr.height * 0.55 ),
1713 ScaleSize( attr.height * 0.6 ) ) );
1714
1715 AlignText( field, attr.textOrigin );
1716
1717 if( add )
1718 footprint->Add( field, ADD_MODE::APPEND );
1719 }
1720 }
1721 else if( type == wxS( "PAD_NET" ) )
1722 {
1723 wxString padNumber = line.at( 2 );
1724 wxString padNet = line.at( 3 );
1725
1726 PAD* pad = footprint->FindPadByNumber( padNumber );
1727 if( pad )
1728 {
1729 pad->SetNet( aBoard->FindNet( padNet ) );
1730 }
1731 else
1732 {
1733 // Not a pad
1734 }
1735 }
1736 }
1737
1738 aBoard->Add( footprint.release(), ADD_MODE::APPEND );
1739 }
1740
1741 // Set zone fills
1743 {
1744 for( auto& [uuid, zone] : poursToFill )
1745 {
1746 SHAPE_POLY_SET fillPolySet;
1747 SHAPE_POLY_SET thermalSpokes;
1748
1749 auto range = boardPouredMap.equal_range( uuid );
1750 for( auto& it = range.first; it != range.second; ++it )
1751 {
1752 const EASYEDAPRO::POURED& poured = it->second;
1753 int unki = poured.unki;
1754
1755 SHAPE_POLY_SET thisPoly;
1756
1757 for( int dataId = 0; dataId < poured.polyData.size(); dataId++ )
1758 {
1759 const nlohmann::json& fillData = poured.polyData[dataId];
1760 const double ptScale = 10;
1761
1762 SHAPE_LINE_CHAIN contour =
1763 ParseContour( fillData, false, ARC_HIGH_DEF / ptScale );
1764
1765 // Scale the fill
1766 for( int i = 0; i < contour.PointCount(); i++ )
1767 contour.SetPoint( i, contour.GetPoint( i ) * ptScale );
1768
1769 if( poured.isPoly )
1770 {
1771 contour.SetClosed( true );
1772
1773 // The contour can be self-intersecting
1774 SHAPE_POLY_SET simple( contour );
1775 simple.Simplify();
1776
1777 if( dataId == 0 )
1778 {
1779 thisPoly.Append( simple );
1780 }
1781 else
1782 {
1783 thisPoly.BooleanSubtract( simple );
1784 }
1785 }
1786 else
1787 {
1788 const int thermalWidth = pcbIUScale.mmToIU( 0.2 ); // Generic
1789
1790 for( int segId = 0; segId < contour.SegmentCount(); segId++ )
1791 {
1792 const SEG& seg = contour.CSegment( segId );
1793
1794 TransformOvalToPolygon( thermalSpokes, seg.A, seg.B, thermalWidth,
1796 }
1797 }
1798 }
1799
1800 fillPolySet.Append( thisPoly );
1801 }
1802
1803 if( !fillPolySet.IsEmpty() )
1804 {
1805 fillPolySet.Simplify();
1806
1807 const int strokeWidth = pcbIUScale.MilsToIU( 8 ); // Seems to be 8 mils
1808
1809 fillPolySet.Inflate( strokeWidth / 2, CORNER_STRATEGY::ROUND_ALL_CORNERS,
1810 ARC_HIGH_DEF, false );
1811
1812 fillPolySet.BooleanAdd( thermalSpokes );
1813
1814 fillPolySet.Fracture();
1815
1816 zone->SetFilledPolysList( zone->GetFirstLayer(), fillPolySet );
1817 zone->SetNeedRefill( false );
1818 zone->SetIsFilled( true );
1819 }
1820 }
1821 }
1822
1823 // Heal board outlines
1824 std::vector<PCB_SHAPE*> shapes;
1825 std::vector<std::unique_ptr<PCB_SHAPE>> newShapes;
1826
1827 for( BOARD_ITEM* item : aBoard->Drawings() )
1828 {
1829 if( !item->IsOnLayer( Edge_Cuts ) )
1830 continue;
1831
1832 if( item->Type() == PCB_SHAPE_T )
1833 shapes.push_back( static_cast<PCB_SHAPE*>( item ) );
1834 }
1835
1836 ConnectBoardShapes( shapes, newShapes, SHAPE_JOIN_DISTANCE );
1837
1838 for( std::unique_ptr<PCB_SHAPE>& ptr : newShapes )
1839 aBoard->Add( ptr.release(), ADD_MODE::APPEND );
1840
1841 // Center the board
1842 BOX2I outlineBbox = aBoard->ComputeBoundingBox( true );
1843 PAGE_INFO pageInfo = aBoard->GetPageSettings();
1844
1845 VECTOR2D pageCenter( pcbIUScale.MilsToIU( pageInfo.GetWidthMils() / 2 ),
1846 pcbIUScale.MilsToIU( pageInfo.GetHeightMils() / 2 ) );
1847
1848 VECTOR2D offset = pageCenter - outlineBbox.GetCenter();
1849
1850 int alignGrid = pcbIUScale.mmToIU( 10 );
1851 offset.x = KiROUND( offset.x / alignGrid ) * alignGrid;
1852 offset.y = KiROUND( offset.y / alignGrid ) * alignGrid;
1853
1854 aBoard->Move( offset );
1855 bds.SetAuxOrigin( offset );
1856}
@ ERROR_INSIDE
Definition: approximation.h:34
constexpr int ARC_HIGH_DEF
Definition: base_units.h:120
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:108
constexpr int ARC_LOW_DEF
Definition: base_units.h:119
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.
Definition: bezier_curves.h:38
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:327
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:290
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:295
LSET GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition: board.cpp:831
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition: board.cpp:1056
void SetEnabledLayers(LSET aLayerMask)
A proxy function that calls the correspondent function in m_BoardSettings.
Definition: board.cpp:851
const PAGE_INFO & GetPageSettings() const
Definition: board.h:706
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition: board.cpp:1992
bool SetLayerName(PCB_LAYER_ID aLayer, const wxString &aLayerName)
Changes the name of the layer given by aLayer.
Definition: board.cpp:634
void Move(const VECTOR2I &aMoveVector) override
Move this object.
Definition: board.cpp:505
BOX2I ComputeBoundingBox(bool aBoardEdgesOnly=false) const
Calculate the bounding box containing all board items (or board edge segments).
Definition: board.cpp:1744
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:948
unsigned GetNetCount() const
Definition: board.h:919
const DRAWINGS & Drawings() const
Definition: board.h:338
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:249
double AsDegrees() const
Definition: eda_angle.h:113
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:80
void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true)
Definition: eda_text.cpp:526
virtual void SetVisible(bool aVisible)
Definition: eda_text.cpp:379
void SetTextThickness(int aWidth)
The TextThickness is that set by the user.
Definition: eda_text.cpp:284
void SetTextAngleDegrees(double aOrientation)
Definition: eda_text.h:137
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:270
void SetFont(KIFONT::FONT *aFont)
Definition: eda_text.cpp:492
PCB_FIELD * GetFieldByName(const wxString &aFieldName)
Return a field in this symbol.
Definition: footprint.cpp:628
PCB_FIELD * AddField(const PCB_FIELD &aField)
Add a field to the symbol.
Definition: footprint.cpp:686
int GetNextFieldId() const
Return the next ID for a field for this footprint.
Definition: footprint.h:742
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition: footprint.cpp:1103
void GetFields(std::vector< PCB_FIELD * > &aVector, bool aVisibleOnly) const
Populate a std::vector with PCB_TEXTs.
Definition: footprint.cpp:680
std::vector< FP_3DMODEL > & Models()
Definition: footprint.h:218
PCB_FIELD * GetField(MANDATORY_FIELD_T aFieldType)
Return a mandatory field in this symbol.
Definition: footprint.cpp:588
DRAWINGS & GraphicalItems()
Definition: footprint.h:207
VECTOR3D m_Offset
3D model offset (mm)
Definition: footprint.h:105
VECTOR3D m_Rotation
3D model rotation (degrees)
Definition: footprint.h:104
wxString m_Filename
The 3D shape filename in 3D library.
Definition: footprint.h:107
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:56
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
Definition: padstack.h:144
Definition: pad.h:54
static LSET PTHMask()
layer set for a through hole pad
Definition: pad.cpp:270
static LSET SMDMask()
layer set for a SMD pad on Front layer
Definition: pad.cpp:277
Describe the page size and margins of a paper page on which to eventually print or plot.
Definition: page_info.h:59
double GetHeightMils() const
Definition: page_info.h:141
double GetWidthMils() const
Definition: page_info.h:136
SHAPE_LINE_CHAIN ParseContour(nlohmann::json polyData, bool aInFill, double aArcAccuracy=SHAPE_ARC::DefaultAccuracyForPCB()) const
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
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:87
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.
Definition: shape_arc.cpp:213
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.
SEG Segment(int aIndex) const
Return a copy of the aIndex-th segment in the 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.
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.
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
Definition: shape_rect.h:212
T y
Definition: vector3.h:64
T z
Definition: vector3.h:65
T x
Definition: vector3.h:63
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)
static constexpr EDA_ANGLE ANGLE_0
Definition: eda_angle.h:401
static constexpr EDA_ANGLE ANGLE_90
Definition: eda_angle.h:403
@ DEGREES_T
Definition: eda_angle.h:31
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)...
#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:743
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: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_3
Definition: layer_ids.h:126
@ 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
@ 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: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
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:390
void Flip(T &aValue)
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 MODEL_SIZE_KEY
static const int SHAPE_JOIN_DISTANCE
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:...
nlohmann::json polyData
constexpr double IUTomm(int iu) const
Definition: base_units.h:86
constexpr int MilsToIU(int mils) const
Definition: base_units.h:93
constexpr int mmToIU(double mm) const
Definition: base_units.h:88
@ REFERENCE_FIELD
Field Reference of part, i.e. "IC21".
VECTOR2I center
const SHAPE_LINE_CHAIN chain
VECTOR2I end
VECTOR2I location
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: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
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:695
VECTOR2< double > VECTOR2D
Definition: vector2d.h:694