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 (C) 2023 KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
27
28#include <memory>
29
30#include <nlohmann/json.hpp>
32#include <core/map_helpers.h>
33#include <string_utils.h>
34
35#include <wx/wfstream.h>
36#include <wx/stdstream.h>
37#include <wx/log.h>
38#include <glm/glm.hpp>
39
40#include <progress_reporter.h>
41#include <footprint.h>
42#include <board.h>
44#include <bezier_curves.h>
45#include <pcb_group.h>
46#include <pcb_track.h>
47#include <pcb_shape.h>
48#include <pcb_text.h>
49#include <font/font.h>
50#include <geometry/shape_arc.h>
53#include <geometry/shape_rect.h>
55#include <zone.h>
56#include <pad.h>
58#include <project.h>
59#include <fix_board_shape.h>
60#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->GetFieldCount(), 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->GetFieldCount(), 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 // TODO: other axes
241 kmodelRotation.z = -Convert( arr[3] );
242
243 kmodelOffset.x = pcbIUScale.IUTomm( ScaleSize( Convert( arr[6] ) ) );
244 kmodelOffset.y = pcbIUScale.IUTomm( ScaleSize( Convert( arr[7] ) ) );
245 kmodelOffset.z = pcbIUScale.IUTomm( ScaleSize( Convert( arr[8] ) ) );
246 }
247
248 if( !modelTitle.IsEmpty() && footprint->Models().empty() )
249 {
250 FP_3DMODEL model;
251 model.m_Filename = kicadModelPrefix
252 + EscapeString( modelTitle, ESCAPE_CONTEXT::CTX_FILENAME )
253 + wxS( ".step" );
254 model.m_Offset = kmodelOffset;
255 model.m_Rotation = kmodelRotation;
256 footprint->Models().push_back( model );
257 }
258}
259
260
261std::vector<std::unique_ptr<PCB_SHAPE>>
262PCB_IO_EASYEDAPRO_PARSER::ParsePoly( BOARD_ITEM_CONTAINER* aContainer, nlohmann::json polyData,
263 bool aClosed, bool aInFill ) const
264{
265 std::vector<std::unique_ptr<PCB_SHAPE>> results;
266
267 VECTOR2D prevPt;
268 for( int i = 0; i < polyData.size(); i++ )
269 {
270 nlohmann::json val = polyData.at( i );
271
272 if( val.is_string() )
273 {
274 wxString str = val;
275 if( str == wxS( "CIRCLE" ) )
276 {
277 VECTOR2D center;
278 center.x = ( polyData.at( ++i ) );
279 center.y = ( polyData.at( ++i ) );
280 double r = ( polyData.at( ++i ) );
281
282 std::unique_ptr<PCB_SHAPE> shape =
283 std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::CIRCLE );
284
285 shape->SetCenter( ScalePos( center ) );
286 shape->SetEnd( ScalePos( center + VECTOR2D( r, 0 ) ) );
287 shape->SetFilled( aClosed );
288
289 results.emplace_back( std::move( shape ) );
290 }
291 else if( str == wxS( "R" ) )
292 {
293 VECTOR2D start, size;
294 start.x = ( polyData.at( ++i ) );
295 start.y = ( polyData.at( ++i ) );
296 size.x = ( polyData.at( ++i ) );
297 size.y = -( polyData.at( ++i ).get<double>() );
298 double angle = polyData.at( ++i );
299 double cr = ( i + 1 ) < polyData.size() ? polyData.at( ++i ).get<double>() : 0;
300
301 if( cr == 0 )
302 {
303 std::unique_ptr<PCB_SHAPE> shape =
304 std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::RECTANGLE );
305
306 shape->SetStart( ScalePos( start ) );
307 shape->SetEnd( ScalePos( start + size ) );
308 shape->SetFilled( aClosed );
309 shape->Rotate( ScalePos( start ), EDA_ANGLE( angle, DEGREES_T ) );
310
311 results.emplace_back( std::move( shape ) );
312 }
313 else
314 {
315 VECTOR2D end = start + size;
316
317 auto addSegment = [&]( VECTOR2D aStart, VECTOR2D aEnd )
318 {
319 std::unique_ptr<PCB_SHAPE> shape =
320 std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::SEGMENT );
321
322 shape->SetStart( ScalePos( aStart ) );
323 shape->SetEnd( ScalePos( aEnd ) );
324 shape->SetFilled( aClosed );
325 shape->Rotate( ScalePos( start ), EDA_ANGLE( angle, DEGREES_T ) );
326
327 results.emplace_back( std::move( shape ) );
328 };
329
330 auto addArc = [&]( VECTOR2D aStart, VECTOR2D aEnd, VECTOR2D center )
331 {
332 std::unique_ptr<PCB_SHAPE> shape =
333 std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::ARC );
334
335 shape->SetStart( ScalePos( aStart ) );
336 shape->SetEnd( ScalePos( aEnd ) );
337 shape->SetCenter( ScalePos( center ) );
338 shape->SetFilled( aClosed );
339 shape->Rotate( ScalePos( start ), EDA_ANGLE( angle, DEGREES_T ) );
340
341 results.emplace_back( std::move( shape ) );
342 };
343
344 addSegment( { start.x + cr, start.y }, { end.x - cr, start.y } );
345 addSegment( { end.x, start.y - cr }, { end.x, end.y + cr } );
346 addSegment( { start.x + cr, end.y }, { end.x - cr, end.y } );
347 addSegment( { start.x, start.y - cr }, { start.x, end.y + cr } );
348
349 addArc( { end.x - cr, start.y }, { end.x, start.y - cr },
350 { end.x - cr, start.y - cr } );
351
352 addArc( { end.x, end.y + cr }, { end.x - cr, end.y },
353 { end.x - cr, end.y + cr } );
354
355 addArc( { start.x + cr, end.y }, { start.x, end.y + cr },
356 { start.x + cr, end.y + cr } );
357
358 addArc( { start.x, start.y - cr }, { start.x + cr, start.y },
359 { start.x + cr, start.y - cr } );
360 }
361 }
362 else if( str == wxS( "ARC" ) || str == wxS( "CARC" ) )
363 {
364 VECTOR2D end;
365 double angle = polyData.at( ++i ).get<double>() / ( aInFill ? 10 : 1 );
366 end.x = ( polyData.at( ++i ) );
367 end.y = ( polyData.at( ++i ) );
368
369 std::unique_ptr<PCB_SHAPE> shape =
370 std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::ARC );
371
372 if( angle < 0 )
373 {
374 shape->SetStart( ScalePos( prevPt ) );
375 shape->SetEnd( ScalePos( end ) );
376 }
377 else
378 {
379 shape->SetStart( ScalePos( end ) );
380 shape->SetEnd( ScalePos( prevPt ) );
381 }
382
383 VECTOR2D delta = end - prevPt;
384 VECTOR2D mid = ( prevPt + delta / 2 );
385
386 double ha = angle / 2;
387 double hd = delta.EuclideanNorm() / 2;
388 double cdist = hd / tan( DEG2RAD( ha ) );
389 VECTOR2D center = mid + delta.Perpendicular().Resize( cdist );
390 shape->SetCenter( ScalePos( center ) );
391
392 shape->SetFilled( aClosed );
393
394 results.emplace_back( std::move( shape ) );
395
396 prevPt = end;
397 }
398 else if( str == wxS( "L" ) )
399 {
400 SHAPE_LINE_CHAIN chain;
401 chain.Append( ScalePos( prevPt ) );
402
403 while( i < polyData.size() - 2 && polyData.at( i + 1 ).is_number() )
404 {
405 VECTOR2D pt;
406 pt.x = ( polyData.at( ++i ) );
407 pt.y = ( polyData.at( ++i ) );
408
409 chain.Append( ScalePos( pt ) );
410
411 prevPt = pt;
412 }
413
414 if( aClosed )
415 {
416 std::unique_ptr<PCB_SHAPE> shape =
417 std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::POLY );
418
419 wxASSERT( chain.PointCount() > 2 );
420
421 if( chain.PointCount() > 2 )
422 {
423 chain.SetClosed( true );
424 shape->SetFilled( true );
425 shape->SetPolyShape( chain );
426
427 results.emplace_back( std::move( shape ) );
428 }
429 }
430 else
431 {
432 for( int s = 0; s < chain.SegmentCount(); s++ )
433 {
434 SEG seg = chain.Segment( s );
435
436 std::unique_ptr<PCB_SHAPE> shape =
437 std::make_unique<PCB_SHAPE>( aContainer, SHAPE_T::SEGMENT );
438
439 shape->SetStart( seg.A );
440 shape->SetEnd( seg.B );
441
442 results.emplace_back( std::move( shape ) );
443 }
444 }
445 }
446 }
447 else if( val.is_number() )
448 {
449 prevPt.x = ( polyData.at( i ) );
450 prevPt.y = ( polyData.at( ++i ) );
451 }
452 }
453
454 return results;
455}
456
457
459PCB_IO_EASYEDAPRO_PARSER::ParseContour( nlohmann::json polyData, bool aInFill,
460 double aArcAccuracy ) const
461{
462 SHAPE_LINE_CHAIN result;
463 VECTOR2D prevPt;
464
465 for( int i = 0; i < polyData.size(); i++ )
466 {
467 nlohmann::json val = polyData.at( i );
468
469 if( val.is_string() )
470 {
471 wxString str = val;
472 if( str == wxS( "CIRCLE" ) )
473 {
474 VECTOR2D center;
475 center.x = ( polyData.at( ++i ) );
476 center.y = ( polyData.at( ++i ) );
477 double r = ( polyData.at( ++i ) );
478
480 ERROR_INSIDE );
481 }
482 else if( str == wxS( "R" ) )
483 {
484 VECTOR2D start, size;
485 start.x = ( polyData.at( ++i ) );
486 start.y = ( polyData.at( ++i ) );
487 size.x = ( polyData.at( ++i ) );
488 size.y = ( polyData.at( ++i ).get<double>() );
489 double angle = polyData.at( ++i );
490 double cr = ( i + 1 ) < polyData.size() ? polyData.at( ++i ).get<double>() : 0;
491
492 SHAPE_POLY_SET poly;
493
494 VECTOR2D kstart = ScalePos( start );
495 VECTOR2D ksize = ScaleSize( size );
496 VECTOR2D kcenter = kstart + ksize / 2;
497 RotatePoint( kcenter, kstart, EDA_ANGLE( angle, DEGREES_T ) );
498
500 poly, kcenter, ksize, EDA_ANGLE( angle, DEGREES_T ), ScaleSize( cr ), 0, 0,
502
503 result.Append( poly.Outline( 0 ) );
504 }
505 else if( str == wxS( "ARC" ) || str == wxS( "CARC" ) )
506 {
507 VECTOR2D end;
508 double angle = polyData.at( ++i ).get<double>();
509
510 if( aInFill ) // In .epcb fills, the angle is 10x for some reason
511 angle /= 10;
512
513 end.x = ( polyData.at( ++i ) );
514 end.y = ( polyData.at( ++i ) );
515
516 VECTOR2D arcStart, arcEnd;
517 arcStart = prevPt;
518 arcEnd = end;
519
520 VECTOR2D delta = end - prevPt;
521 VECTOR2D mid = ( prevPt + delta / 2 );
522
523 double ha = angle / 2;
524 double hd = delta.EuclideanNorm() / 2;
525 double cdist = hd / tan( DEG2RAD( ha ) );
526 VECTOR2D center = mid + delta.Perpendicular().Resize( cdist );
527
528 SHAPE_ARC sarc;
529 sarc.ConstructFromStartEndCenter( ScalePos( arcStart ), ScalePos( arcEnd ),
530 ScalePos( center ), angle >= 0, 0 );
531
532 result.Append( sarc, aArcAccuracy );
533
534 prevPt = end;
535 }
536 else if( str == wxS( "C" ) )
537 {
538 VECTOR2D pt1;
539 pt1.x = ( polyData.at( ++i ) );
540 pt1.y = ( polyData.at( ++i ) );
541
542 VECTOR2D pt2;
543 pt2.x = ( polyData.at( ++i ) );
544 pt2.y = ( polyData.at( ++i ) );
545
546 VECTOR2D pt3;
547 pt3.x = ( polyData.at( ++i ) );
548 pt3.y = ( polyData.at( ++i ) );
549
550 std::vector<VECTOR2I> ctrlPoints = { ScalePos( prevPt ), ScalePos( pt1 ),
551 ScalePos( pt2 ), ScalePos( pt3 ) };
552 BEZIER_POLY converter( ctrlPoints );
553
554 std::vector<VECTOR2I> bezierPoints;
555 converter.GetPoly( bezierPoints, aArcAccuracy );
556
557 result.Append( bezierPoints );
558
559 prevPt = pt3;
560 }
561 else if( str == wxS( "L" ) )
562 {
563 result.Append( ScalePos( prevPt ) );
564
565 while( i < polyData.size() - 2 && polyData.at( i + 1 ).is_number() )
566 {
567 VECTOR2D pt;
568 pt.x = ( polyData.at( ++i ) );
569 pt.y = ( polyData.at( ++i ) );
570
571 result.Append( ScalePos( pt ) );
572
573 prevPt = pt;
574 }
575 }
576 }
577 else if( val.is_number() )
578 {
579 prevPt.x = ( polyData.at( i ) );
580 prevPt.y = ( polyData.at( ++i ) );
581 }
582 }
583
584 return result;
585}
586
587
588std::unique_ptr<PAD> PCB_IO_EASYEDAPRO_PARSER::createPAD( FOOTPRINT* aFootprint,
589 const nlohmann::json& line )
590{
591 wxString uuid = line.at( 1 );
592
593 // if( line.at( 2 ).is_number() )
594 // int unk = line.at( 2 ).get<int>();
595 // else if( line.at( 2 ).is_string() )
596 // int unk = wxAtoi( line.at( 2 ).get<wxString>() );
597
598 wxString netname = line.at( 3 );
599 int layer = line.at( 4 ).get<int>();
600 PCB_LAYER_ID klayer = LayerToKi( layer );
601
602 wxString padNumber = line.at( 5 );
603
604 VECTOR2D center;
605 center.x = line.at( 6 );
606 center.y = line.at( 7 );
607
608 double orientation = line.at( 8 );
609
610 nlohmann::json padHole = line.at( 9 );
611 nlohmann::json padShape = line.at( 10 );
612
613 std::unique_ptr<PAD> pad = std::make_unique<PAD>( aFootprint );
614
615 pad->SetNumber( padNumber );
616 pad->SetPosition( ScalePos( center ) );
617 pad->SetOrientationDegrees( orientation );
618
619 if( !padHole.is_null() )
620 {
621 double drill_dir = 0;
622
623 if( line.at( 14 ).is_number() )
624 drill_dir = line.at( 14 );
625
626 wxString holeShape = padHole.at( 0 );
627
628 if( holeShape == wxS( "ROUND" ) || holeShape == wxS( "SLOT" ) )
629 {
630 VECTOR2D drill;
631 drill.x = padHole.at( 1 );
632 drill.y = padHole.at( 2 );
633
634 double deg = EDA_ANGLE( drill_dir, DEGREES_T ).Normalize90().AsDegrees();
635
636 if( std::abs( deg ) >= 45 )
637 std::swap( drill.x, drill.y ); // KiCad doesn't support arbitrary hole direction
638
639 if( holeShape == wxS( "SLOT" ) )
640 {
641 pad->SetDrillShape( PAD_DRILL_SHAPE::OBLONG );
642 }
643
644 pad->SetDrillSize( ScaleSize( drill ) );
645 pad->SetLayerSet( PAD::PTHMask() );
646 pad->SetAttribute( PAD_ATTRIB::PTH );
647 }
648 }
649 else
650 {
651 if( klayer == F_Cu )
652 {
653 pad->SetLayerSet( PAD::SMDMask() );
654 }
655 else if( klayer == B_Cu )
656 {
657 pad->SetLayerSet( PAD::SMDMask().Flip() );
658 }
659
660 pad->SetAttribute( PAD_ATTRIB::SMD );
661 }
662
663 wxString padSh = padShape.at( 0 );
664 if( padSh == wxS( "RECT" ) )
665 {
666 VECTOR2D size;
667 size.x = padShape.at( 1 );
668 size.y = padShape.at( 2 );
669 double cr_p = padShape.size() > 3 ? padShape.at( 3 ).get<double>() : 0;
670
671 pad->SetSize( PADSTACK::ALL_LAYERS, ScaleSize( size ) );
672
673 if( cr_p == 0 )
674 {
675 pad->SetShape( PADSTACK::ALL_LAYERS, PAD_SHAPE::RECTANGLE );
676 }
677 else
678 {
679 pad->SetShape( PADSTACK::ALL_LAYERS, PAD_SHAPE::ROUNDRECT );
680 pad->SetRoundRectRadiusRatio( PADSTACK::ALL_LAYERS, cr_p / 100 );
681 }
682 }
683 else if( padSh == wxS( "ELLIPSE" ) )
684 {
685 VECTOR2D size;
686 size.x = padShape.at( 1 );
687 size.y = padShape.at( 2 );
688
689 pad->SetSize( PADSTACK::ALL_LAYERS, ScaleSize( size ) );
690 pad->SetShape( PADSTACK::ALL_LAYERS, PAD_SHAPE::CIRCLE );
691 }
692 else if( padSh == wxS( "OVAL" ) )
693 {
694 VECTOR2D size;
695 size.x = padShape.at( 1 );
696 size.y = padShape.at( 2 );
697
698 pad->SetSize( PADSTACK::ALL_LAYERS, ScaleSize( size ) );
699 pad->SetShape( PADSTACK::ALL_LAYERS, PAD_SHAPE::OVAL );
700 }
701 else if( padSh == wxS( "POLY" ) )
702 {
703 pad->SetShape( PADSTACK::ALL_LAYERS, PAD_SHAPE::CUSTOM );
704 pad->SetAnchorPadShape( PADSTACK::ALL_LAYERS, PAD_SHAPE::CIRCLE );
705 pad->SetSize( PADSTACK::ALL_LAYERS, { 1, 1 } );
706
707 nlohmann::json polyData = padShape.at( 1 );
708
709 std::vector<std::unique_ptr<PCB_SHAPE>> results =
710 ParsePoly( aFootprint, polyData, true, false );
711
712 for( auto& shape : results )
713 {
714 shape->SetLayer( klayer );
715 shape->SetWidth( 0 );
716
717 shape->Move( -pad->GetPosition() );
718
719 pad->AddPrimitive( PADSTACK::ALL_LAYERS, shape.release() );
720 }
721 }
722
723 pad->SetThermalSpokeAngle( ANGLE_90 );
724
725 return std::move( pad );
726}
727
728
730 const wxString& aFpUuid,
731 const std::vector<nlohmann::json>& aLines )
732{
733 std::unique_ptr<FOOTPRINT> footprintPtr = std::make_unique<FOOTPRINT>( m_board );
734 FOOTPRINT* footprint = footprintPtr.get();
735
736 const VECTOR2I defaultTextSize( pcbIUScale.mmToIU( 1.0 ), pcbIUScale.mmToIU( 1.0 ) );
737 const int defaultTextThickness( pcbIUScale.mmToIU( 0.15 ) );
738
739 for( PCB_FIELD* field : footprint->Fields() )
740 {
741 field->SetTextSize( defaultTextSize );
742 field->SetTextThickness( defaultTextThickness );
743 }
744
745 for( const nlohmann::json& line : aLines )
746 {
747 if( line.size() == 0 )
748 continue;
749
750 wxString type = line.at( 0 );
751
752 if( type == wxS( "POLY" ) || type == wxS( "PAD" ) || type == wxS( "FILL" )
753 || type == wxS( "ATTR" ) )
754 {
755 wxString uuid = line.at( 1 );
756
757 // if( line.at( 2 ).is_number() )
758 // int unk = line.at( 2 ).get<int>();
759 // else if( line.at( 2 ).is_string() )
760 // int unk = wxAtoi( line.at( 2 ).get<wxString>() );
761
762 wxString netname = line.at( 3 );
763 int layer = line.at( 4 ).get<int>();
764 PCB_LAYER_ID klayer = LayerToKi( layer );
765
766 if( type == wxS( "POLY" ) )
767 {
768 double thickness = ( line.at( 5 ) );
769 nlohmann::json polyData = line.at( 6 );
770
771 std::vector<std::unique_ptr<PCB_SHAPE>> results =
772 ParsePoly( footprint, polyData, false, false );
773
774 for( auto& shape : results )
775 {
776 shape->SetLayer( klayer );
777 shape->SetWidth( ScaleSize( thickness ) );
778
779 footprint->Add( shape.release(), ADD_MODE::APPEND );
780 }
781 }
782 else if( type == wxS( "PAD" ) )
783 {
784 std::unique_ptr<PAD> pad = createPAD( footprint, line );
785
786 footprint->Add( pad.release(), ADD_MODE::APPEND );
787 }
788 else if( type == wxS( "FILL" ) )
789 {
790 int layer = line.at( 4 ).get<int>();
791 PCB_LAYER_ID klayer = LayerToKi( layer );
792
793 double width = line.at( 5 );
794
795 nlohmann::json polyDataList = line.at( 7 );
796
797 if( !polyDataList.is_null() && !polyDataList.empty() )
798 {
799 if( !polyDataList.at( 0 ).is_array() )
800 polyDataList = nlohmann::json::array( { polyDataList } );
801
802 std::vector<SHAPE_LINE_CHAIN> contours;
803 for( nlohmann::json& polyData : polyDataList )
804 {
805 SHAPE_LINE_CHAIN contour = ParseContour( polyData, false );
806 contour.SetClosed( true );
807
808 contours.push_back( contour );
809 }
810
811 SHAPE_POLY_SET polySet;
812
813 for( SHAPE_LINE_CHAIN& contour : contours )
814 polySet.AddOutline( contour );
815
816 polySet.RebuildHolesFromContours();
817
818 std::unique_ptr<PCB_GROUP> group;
819
820 if( polySet.OutlineCount() > 1 )
821 group = std::make_unique<PCB_GROUP>( footprint );
822
823 BOX2I polyBBox = polySet.BBox();
824
825 for( const SHAPE_POLY_SET::POLYGON& poly : polySet.CPolygons() )
826 {
827 std::unique_ptr<PCB_SHAPE> shape =
828 std::make_unique<PCB_SHAPE>( footprint, SHAPE_T::POLY );
829
830 shape->SetFilled( true );
831 shape->SetPolyShape( poly );
832 shape->SetLayer( klayer );
833 shape->SetWidth( 0 );
834
835 if( group )
836 group->AddItem( shape.get() );
837
838 footprint->Add( shape.release(), ADD_MODE::APPEND );
839 }
840
841 if( group )
842 footprint->Add( group.release(), ADD_MODE::APPEND );
843 }
844 }
845 else if( type == wxS( "ATTR" ) )
846 {
847 EASYEDAPRO::PCB_ATTR attr = line;
848
849 if( attr.key == wxS( "Designator" ) )
850 footprint->GetField( REFERENCE_FIELD )->SetText( attr.value );
851 }
852 }
853 else if( type == wxS( "REGION" ) )
854 {
855 wxString uuid = line.at( 1 );
856
857 // if( line.at( 2 ).is_number() )
858 // int unk = line.at( 2 ).get<int>();
859 // else if( line.at( 2 ).is_string() )
860 // int unk = wxAtoi( line.at( 2 ).get<wxString>() );
861
862 int layer = line.at( 3 ).get<int>();
863 PCB_LAYER_ID klayer = LayerToKi( layer );
864
865 double width = line.at( 4 );
866 std::set<int> flags = line.at( 5 );
867 nlohmann::json polyDataList = line.at( 6 );
868
869 for( nlohmann::json& polyData : polyDataList )
870 {
871 SHAPE_POLY_SET polySet;
872
873 std::vector<std::unique_ptr<PCB_SHAPE>> results =
874 ParsePoly( nullptr, polyData, true, false );
875
876 for( auto& shape : results )
877 {
878 shape->SetFilled( true );
879 shape->TransformShapeToPolygon( polySet, klayer, 0, ARC_HIGH_DEF, ERROR_INSIDE,
880 true );
881 }
882
884
885 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>( footprint );
886
887 zone->SetIsRuleArea( true );
888 zone->SetDoNotAllowFootprints( !!flags.count( 2 ) );
889 zone->SetDoNotAllowCopperPour( !!flags.count( 7 ) || !!flags.count( 6 )
890 || !!flags.count( 8 ) );
891 zone->SetDoNotAllowPads( !!flags.count( 7 ) );
892 zone->SetDoNotAllowTracks( !!flags.count( 7 ) || !!flags.count( 5 ) );
893 zone->SetDoNotAllowVias( !!flags.count( 7 ) );
894
895 zone->SetLayer( klayer );
896 zone->Outline()->Append( polySet );
897
898 footprint->Add( zone.release(), ADD_MODE::APPEND );
899 }
900 }
901 }
902
903 if( aProject.is_object() && aProject.contains( "devices" ) )
904 {
905 std::map<wxString, EASYEDAPRO::PRJ_DEVICE> devicesMap = aProject.at( "devices" );
906 std::map<wxString, wxString> compAttrs;
907
908 for( auto& [devUuid, devData] : devicesMap )
909 {
910 if( auto fp = get_opt( devData.attributes, "Footprint" ) )
911 {
912 if( *fp == aFpUuid )
913 {
914 compAttrs = devData.attributes;
915 break;
916 }
917 }
918 }
919
920 wxString modelUuid, modelTitle, modelTransform;
921
922 modelUuid = get_def( compAttrs, "3D Model", "" );
923 modelTitle = get_def( compAttrs, "3D Model Title", modelUuid );
924 modelTransform = get_def( compAttrs, "3D Model Transform", "" );
925
926 fillFootprintModelInfo( footprint, modelUuid, modelTitle, modelTransform );
927 }
928
929 // Heal board outlines
930 std::vector<PCB_SHAPE*> shapes;
931 std::vector<std::unique_ptr<PCB_SHAPE>> newShapes;
932
933 for( BOARD_ITEM* item : footprint->GraphicalItems() )
934 {
935 if( !item->IsOnLayer( Edge_Cuts ) )
936 continue;
937
938 if( item->Type() == PCB_SHAPE_T )
939 shapes.push_back( static_cast<PCB_SHAPE*>( item ) );
940 }
941
942 ConnectBoardShapes( shapes, newShapes, SHAPE_JOIN_DISTANCE );
943
944 for( std::unique_ptr<PCB_SHAPE>& ptr : newShapes )
945 footprint->Add( ptr.release(), ADD_MODE::APPEND );
946
947 return footprintPtr.release();
948}
949
950
952 BOARD* aBoard, const nlohmann::json& aProject,
953 std::map<wxString, std::unique_ptr<FOOTPRINT>>& aFootprintMap,
954 const std::map<wxString, EASYEDAPRO::BLOB>& aBlobMap,
955 const std::multimap<wxString, EASYEDAPRO::POURED>& aPouredMap,
956 const std::vector<nlohmann::json>& aLines, const wxString& aFpLibName )
957{
958 std::map<wxString, std::vector<nlohmann::json>> componentLines;
959 std::map<wxString, std::vector<nlohmann::json>> ruleLines;
960
961 std::multimap<wxString, EASYEDAPRO::POURED> boardPouredMap = aPouredMap;
962 std::map<wxString, ZONE*> poursToFill;
963
965
966 for( const nlohmann::json& line : aLines )
967 {
968 if( line.size() == 0 )
969 continue;
970
971 wxString type = line.at( 0 );
972
973 if( type == wxS( "LAYER" ) )
974 {
975 int layer = line.at( 1 );
976 PCB_LAYER_ID klayer = LayerToKi( layer );
977
978 wxString layerType = line.at( 2 );
979 wxString layerName = line.at( 3 );
980 int layerFlag = line.at( 4 );
981
982 if( layerFlag != 0 )
983 {
984 LSET blayers = aBoard->GetEnabledLayers();
985 blayers.set( klayer );
986 aBoard->SetEnabledLayers( blayers );
987 aBoard->SetLayerName( klayer, layerName );
988 }
989 }
990 else if( type == wxS( "NET" ) )
991 {
992 wxString netname = line.at( 1 );
993
994 aBoard->Add( new NETINFO_ITEM( aBoard, netname, aBoard->GetNetCount() + 1 ),
995 ADD_MODE::APPEND );
996 }
997 else if( type == wxS( "RULE" ) )
998 {
999 wxString ruleType = line.at( 1 );
1000 wxString ruleName = line.at( 2 );
1001 int isDefault = line.at( 3 );
1002 nlohmann::json ruleData = line.at( 4 );
1003
1004 if( ruleType == wxS( "3" ) && isDefault ) // Track width
1005 {
1006 wxString units = ruleData.at( 0 );
1007 double minVal = ruleData.at( 1 );
1008 double optVal = ruleData.at( 2 );
1009 double maxVal = ruleData.at( 3 );
1010
1011 bds.m_TrackMinWidth = ScaleSize( minVal );
1012 }
1013 else if( ruleType == wxS( "1" ) && isDefault )
1014 {
1015 wxString units = ruleData.at( 0 );
1016 nlohmann::json table = ruleData.at( 1 );
1017
1018 int minVal = INT_MAX;
1019 for( const std::vector<int>& arr : table )
1020 {
1021 for( int val : arr )
1022 {
1023 if( val < minVal )
1024 minVal = val;
1025 }
1026 }
1027
1028 bds.m_MinClearance = ScaleSize( minVal );
1029 }
1030
1031 ruleLines[ruleType].push_back( line );
1032 }
1033 else if( type == wxS( "POURED" ) )
1034 {
1035 if( !line.at( 2 ).is_string() )
1036 continue; // Unknown type of POURED
1037
1038 EASYEDAPRO::POURED poured = line;
1039 boardPouredMap.emplace( poured.parentId, poured );
1040 }
1041 else if( type == wxS( "VIA" ) || type == wxS( "LINE" ) || type == wxS( "ARC" )
1042 || type == wxS( "POLY" ) || type == wxS( "FILL" ) || type == wxS( "POUR" ) )
1043 {
1044 wxString uuid = line.at( 1 );
1045
1046 // if( line.at( 2 ).is_number() )
1047 // int unk = line.at( 2 ).get<int>();
1048 // else if( line.at( 2 ).is_string() )
1049 // int unk = wxAtoi( line.at( 2 ).get<wxString>() );
1050
1051 wxString netname = line.at( 3 );
1052
1053 if( type == wxS( "VIA" ) )
1054 {
1055 VECTOR2D center;
1056 center.x = line.at( 5 );
1057 center.y = line.at( 6 );
1058
1059 double drill = line.at( 7 );
1060 double dia = line.at( 8 );
1061
1062 std::unique_ptr<PCB_VIA> via = std::make_unique<PCB_VIA>( aBoard );
1063
1064 via->SetPosition( ScalePos( center ) );
1065 via->SetDrill( ScaleSize( drill ) );
1066 via->SetWidth( PADSTACK::ALL_LAYERS, ScaleSize( dia ) );
1067
1068 via->SetNet( aBoard->FindNet( netname ) );
1069
1070 aBoard->Add( via.release(), ADD_MODE::APPEND );
1071 }
1072 else if( type == wxS( "LINE" ) )
1073 {
1074 int layer = line.at( 4 ).get<int>();
1075 PCB_LAYER_ID klayer = LayerToKi( layer );
1076
1077 VECTOR2D start;
1078 start.x = line.at( 5 );
1079 start.y = line.at( 6 );
1080
1081 VECTOR2D end;
1082 end.x = line.at( 7 );
1083 end.y = line.at( 8 );
1084
1085 double width = line.at( 9 );
1086
1087 std::unique_ptr<PCB_TRACK> track = std::make_unique<PCB_TRACK>( aBoard );
1088
1089 track->SetLayer( klayer );
1090 track->SetStart( ScalePos( start ) );
1091 track->SetEnd( ScalePos( end ) );
1092 track->SetWidth( ScaleSize( width ) );
1093
1094 track->SetNet( aBoard->FindNet( netname ) );
1095
1096 aBoard->Add( track.release(), ADD_MODE::APPEND );
1097 }
1098 else if( type == wxS( "ARC" ) )
1099 {
1100 int layer = line.at( 4 ).get<int>();
1101 PCB_LAYER_ID klayer = LayerToKi( layer );
1102
1103 VECTOR2D start;
1104 start.x = line.at( 5 );
1105 start.y = line.at( 6 );
1106
1107 VECTOR2D end;
1108 end.x = line.at( 7 );
1109 end.y = line.at( 8 );
1110
1111 double angle = line.at( 9 );
1112 double width = line.at( 10 );
1113
1114 VECTOR2D delta = end - start;
1115 VECTOR2D mid = ( start + delta / 2 );
1116
1117 double ha = angle / 2;
1118 double hd = delta.EuclideanNorm() / 2;
1119 double cdist = hd / tan( DEG2RAD( ha ) );
1120 VECTOR2D center = mid + delta.Perpendicular().Resize( cdist );
1121
1122 SHAPE_ARC sarc;
1123 sarc.ConstructFromStartEndCenter( ScalePos( start ), ScalePos( end ),
1124 ScalePos( center ), angle >= 0, width );
1125
1126 std::unique_ptr<PCB_ARC> arc = std::make_unique<PCB_ARC>( aBoard, &sarc );
1127 arc->SetWidth( ScaleSize( width ) );
1128
1129 arc->SetLayer( klayer );
1130 arc->SetNet( aBoard->FindNet( netname ) );
1131
1132 aBoard->Add( arc.release(), ADD_MODE::APPEND );
1133 }
1134 else if( type == wxS( "FILL" ) )
1135 {
1136 int layer = line.at( 4 ).get<int>();
1137 PCB_LAYER_ID klayer = LayerToKi( layer );
1138
1139 double width = line.at( 5 );
1140
1141 nlohmann::json polyDataList = line.at( 7 );
1142
1143 if( !polyDataList.at( 0 ).is_array() )
1144 polyDataList = nlohmann::json::array( { polyDataList } );
1145
1146 std::vector<SHAPE_LINE_CHAIN> contours;
1147 for( nlohmann::json& polyData : polyDataList )
1148 {
1149 SHAPE_LINE_CHAIN contour = ParseContour( polyData, true );
1150 contour.SetClosed( true );
1151
1152 contours.push_back( contour );
1153 }
1154
1155 SHAPE_POLY_SET zoneFillPoly;
1156
1157 for( SHAPE_LINE_CHAIN& contour : contours )
1158 zoneFillPoly.AddOutline( contour );
1159
1160 zoneFillPoly.RebuildHolesFromContours();
1162
1163 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>( aBoard );
1164
1165 zone->SetNet( aBoard->FindNet( netname ) );
1166 zone->SetLayer( klayer );
1167 zone->Outline()->Append( SHAPE_RECT( zoneFillPoly.BBox() ).Outline() );
1168 zone->SetFilledPolysList( klayer, zoneFillPoly );
1169 zone->SetAssignedPriority( 500 );
1170 zone->SetIsFilled( true );
1171 zone->SetNeedRefill( false );
1172
1173 zone->SetLocalClearance( bds.m_MinClearance );
1174 zone->SetMinThickness( bds.m_TrackMinWidth );
1175
1176 aBoard->Add( zone.release(), ADD_MODE::APPEND );
1177 }
1178 else if( type == wxS( "POLY" ) )
1179 {
1180 int layer = line.at( 4 );
1181 PCB_LAYER_ID klayer = LayerToKi( layer );
1182
1183 double thickness = line.at( 5 );
1184 nlohmann::json polyData = line.at( 6 );
1185
1186 std::vector<std::unique_ptr<PCB_SHAPE>> results =
1187 ParsePoly( aBoard, polyData, false, false );
1188
1189 for( auto& shape : results )
1190 {
1191 shape->SetLayer( klayer );
1192 shape->SetWidth( ScaleSize( thickness ) );
1193
1194 aBoard->Add( shape.release(), ADD_MODE::APPEND );
1195 }
1196 }
1197 else if( type == wxS( "POUR" ) )
1198 {
1199 int layer = line.at( 4 ).get<int>();
1200 PCB_LAYER_ID klayer = LayerToKi( layer );
1201
1202 double lineWidth = line.at( 5 ); // Doesn't matter
1203 wxString pourname = line.at( 6 );
1204 int fillOrder = line.at( 7 ).get<int>();
1205 nlohmann::json polyDataList = line.at( 8 );
1206
1207 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>( aBoard );
1208
1209 zone->SetNet( aBoard->FindNet( netname ) );
1210 zone->SetLayer( klayer );
1211 zone->SetAssignedPriority( 500 - fillOrder );
1212 zone->SetLocalClearance( bds.m_MinClearance );
1213 zone->SetMinThickness( bds.m_TrackMinWidth );
1214
1215 for( nlohmann::json& polyData : polyDataList )
1216 {
1217 SHAPE_LINE_CHAIN contour = ParseContour( polyData, false );
1218 contour.SetClosed( true );
1219
1220 zone->Outline()->Append( contour );
1221 }
1222
1223 wxASSERT( zone->Outline()->OutlineCount() == 1 );
1224
1225 poursToFill.emplace( uuid, zone.get() );
1226
1227 aBoard->Add( zone.release(), ADD_MODE::APPEND );
1228 }
1229 }
1230 else if( type == wxS( "TEARDROP" ) )
1231 {
1232 wxString uuid = line.at( 1 );
1233 wxString netname = line.at( 2 );
1234 int layer = line.at( 3 ).get<int>();
1235 PCB_LAYER_ID klayer = LayerToKi( layer );
1236
1237 nlohmann::json polyData = line.at( 4 );
1238
1239 SHAPE_LINE_CHAIN contour = ParseContour( polyData, false );
1240 contour.SetClosed( true );
1241
1242 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>( aBoard );
1243
1244 zone->SetNet( aBoard->FindNet( netname ) );
1245 zone->SetLayer( klayer );
1246 zone->Outline()->Append( contour );
1247 zone->SetFilledPolysList( klayer, contour );
1248 zone->SetNeedRefill( false );
1249 zone->SetIsFilled( true );
1250
1251 zone->SetAssignedPriority( 600 );
1252 zone->SetLocalClearance( 0 );
1253 zone->SetMinThickness( 0 );
1254 zone->SetTeardropAreaType( TEARDROP_TYPE::TD_UNSPECIFIED );
1255
1256 aBoard->Add( zone.release(), ADD_MODE::APPEND );
1257 }
1258 else if( type == wxS( "REGION" ) )
1259 {
1260 wxString uuid = line.at( 1 );
1261
1262 // if( line.at( 2 ).is_number() )
1263 // int unk = line.at( 2 ).get<int>();
1264 // else if( line.at( 2 ).is_string() )
1265 // int unk = wxAtoi( line.at( 2 ).get<wxString>() );
1266
1267 int layer = line.at( 3 ).get<int>();
1268 PCB_LAYER_ID klayer = LayerToKi( layer );
1269
1270 double width = line.at( 4 );
1271 std::set<int> flags = line.at( 5 );
1272 nlohmann::json polyDataList = line.at( 6 );
1273
1274 for( nlohmann::json& polyData : polyDataList )
1275 {
1276 SHAPE_LINE_CHAIN contour = ParseContour( polyData, false );
1277 contour.SetClosed( true );
1278
1279 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>( aBoard );
1280
1281 zone->SetIsRuleArea( true );
1282 zone->SetDoNotAllowFootprints( !!flags.count( 2 ) );
1283 zone->SetDoNotAllowCopperPour( !!flags.count( 7 ) || !!flags.count( 6 )
1284 || !!flags.count( 8 ) );
1285 zone->SetDoNotAllowPads( !!flags.count( 7 ) );
1286 zone->SetDoNotAllowTracks( !!flags.count( 7 ) || !!flags.count( 5 ) );
1287 zone->SetDoNotAllowVias( !!flags.count( 7 ) );
1288
1289 zone->SetLayer( klayer );
1290 zone->Outline()->Append( contour );
1291
1292 aBoard->Add( zone.release(), ADD_MODE::APPEND );
1293 }
1294 }
1295 else if( type == wxS( "PAD" ) )
1296 {
1297 wxString netname = line.at( 3 );
1298
1299 std::unique_ptr<FOOTPRINT> footprint = std::make_unique<FOOTPRINT>( aBoard );
1300 std::unique_ptr<PAD> pad = createPAD( footprint.get(), line );
1301
1302 pad->SetNet( aBoard->FindNet( netname ) );
1303
1304 VECTOR2I pos = pad->GetPosition();
1305 EDA_ANGLE orient = pad->GetOrientation();
1306
1307 pad->SetPosition( VECTOR2I() );
1308 pad->SetOrientation( ANGLE_0 );
1309
1310 footprint->Add( pad.release(), ADD_MODE::APPEND );
1311 footprint->SetPosition( pos );
1312 footprint->SetOrientation( orient );
1313
1314 wxString fpName = wxS( "Pad_" ) + line.at( 1 ).get<wxString>();
1315 LIB_ID fpID = EASYEDAPRO::ToKiCadLibID( wxEmptyString, fpName );
1316
1317 footprint->SetFPID( fpID );
1318 footprint->Reference().SetVisible( true );
1319 footprint->Value().SetVisible( true );
1320 footprint->AutoPositionFields();
1321
1322 aBoard->Add( footprint.release(), ADD_MODE::APPEND );
1323 }
1324 else if( type == wxS( "IMAGE" ) )
1325 {
1326 wxString uuid = line.at( 1 );
1327
1328 // if( line.at( 2 ).is_number() )
1329 // int unk = line.at( 2 ).get<int>();
1330 // else if( line.at( 2 ).is_string() )
1331 // int unk = wxAtoi( line.at( 2 ).get<wxString>() );
1332
1333 int layer = line.at( 3 ).get<int>();
1334 PCB_LAYER_ID klayer = LayerToKi( layer );
1335
1336 VECTOR2D start( line.at( 4 ), line.at( 5 ) );
1337 VECTOR2D size( line.at( 6 ), line.at( 7 ) );
1338
1339 double angle = line.at( 8 ); // from top left corner
1340 int mirror = line.at( 9 );
1341 nlohmann::json polyDataList = line.at( 10 );
1342
1343 BOX2I bbox;
1344 std::vector<SHAPE_LINE_CHAIN> contours;
1345 for( nlohmann::json& polyData : polyDataList )
1346 {
1347 SHAPE_LINE_CHAIN contour = ParseContour( polyData, false );
1348 contour.SetClosed( true );
1349
1350 contours.push_back( contour );
1351
1352 bbox.Merge( contour.BBox() );
1353 }
1354
1355 VECTOR2D scale( ScaleSize( size.x ) / bbox.GetSize().x,
1356 ScaleSize( size.y ) / bbox.GetSize().y );
1357
1358 SHAPE_POLY_SET polySet;
1359
1360 for( SHAPE_LINE_CHAIN& contour : contours )
1361 {
1362 for( int i = 0; i < contour.PointCount(); i++ )
1363 {
1364 VECTOR2I pt = contour.CPoint( i );
1365 contour.SetPoint( i, VECTOR2I( pt.x * scale.x, pt.y * scale.y ) );
1366 }
1367
1368 polySet.AddOutline( contour );
1369 }
1370
1371 polySet.RebuildHolesFromContours();
1372
1373 std::unique_ptr<PCB_GROUP> group;
1374
1375 if( polySet.OutlineCount() > 1 )
1376 group = std::make_unique<PCB_GROUP>( aBoard );
1377
1378 BOX2I polyBBox = polySet.BBox();
1379
1380 for( const SHAPE_POLY_SET::POLYGON& poly : polySet.CPolygons() )
1381 {
1382 std::unique_ptr<PCB_SHAPE> shape =
1383 std::make_unique<PCB_SHAPE>( aBoard, SHAPE_T::POLY );
1384
1385 shape->SetFilled( true );
1386 shape->SetPolyShape( poly );
1387 shape->SetLayer( klayer );
1388 shape->SetWidth( 0 );
1389
1390 shape->Move( ScalePos( start ) - polyBBox.GetOrigin() );
1391 shape->Rotate( ScalePos( start ), EDA_ANGLE( angle, DEGREES_T ) );
1392
1393 if( IsBackLayer( klayer ) ^ !!mirror )
1394 {
1395 FLIP_DIRECTION flipDirection = IsBackLayer( klayer )
1396 ? FLIP_DIRECTION::TOP_BOTTOM
1397 : FLIP_DIRECTION::LEFT_RIGHT;
1398 shape->Mirror( ScalePos( start ), flipDirection );
1399 }
1400
1401 if( group )
1402 group->AddItem( shape.get() );
1403
1404 aBoard->Add( shape.release(), ADD_MODE::APPEND );
1405 }
1406
1407 if( group )
1408 aBoard->Add( group.release(), ADD_MODE::APPEND );
1409 }
1410 else if( type == wxS( "OBJ" ) )
1411 {
1412 VECTOR2D start, size;
1413 wxString mimeType, base64Data;
1414 double angle = 0;
1415 int flipped = 0;
1416
1417 if( !line.at( 3 ).is_number() )
1418 continue;
1419
1420 int layer = line.at( 3 ).get<int>();
1421 PCB_LAYER_ID klayer = LayerToKi( layer );
1422
1423 start = VECTOR2D( line.at( 5 ), line.at( 6 ) );
1424 size = VECTOR2D( line.at( 7 ), line.at( 8 ) );
1425 angle = line.at( 9 );
1426 flipped = line.at( 10 );
1427
1428 wxString imageUrl = line.at( 11 );
1429
1430 if( imageUrl.BeforeFirst( ':' ) == wxS( "blob" ) )
1431 {
1432 wxString objectId = imageUrl.AfterLast( ':' );
1433
1434 if( auto blob = get_opt( aBlobMap, objectId ) )
1435 {
1436 wxString blobUrl = blob->url;
1437
1438 if( blobUrl.BeforeFirst( ':' ) == wxS( "data" ) )
1439 {
1440 wxArrayString paramsArr =
1441 wxSplit( blobUrl.AfterFirst( ':' ).BeforeFirst( ',' ), ';', '\0' );
1442
1443 base64Data = blobUrl.AfterFirst( ',' );
1444
1445 if( paramsArr.size() > 0 )
1446 mimeType = paramsArr[0];
1447 }
1448 }
1449 }
1450
1451 VECTOR2D kstart = ScalePos( start );
1452 VECTOR2D ksize = ScaleSize( size );
1453
1454 if( mimeType.empty() || base64Data.empty() )
1455 continue;
1456
1457 wxMemoryBuffer buf = wxBase64Decode( base64Data );
1458
1459 if( mimeType == wxS( "image/svg+xml" ) )
1460 {
1461 // Not yet supported by EasyEDA
1462 }
1463 else
1464 {
1465 VECTOR2D kcenter = kstart + ksize / 2;
1466
1467 std::unique_ptr<PCB_REFERENCE_IMAGE> bitmap =
1468 std::make_unique<PCB_REFERENCE_IMAGE>( aBoard, kcenter, klayer );
1469 REFERENCE_IMAGE& refImage = bitmap->GetReferenceImage();
1470
1471 wxImage::SetDefaultLoadFlags( wxImage::GetDefaultLoadFlags()
1472 & ~wxImage::Load_Verbose );
1473
1474 if( refImage.ReadImageFile( buf ) )
1475 {
1476 double scaleFactor = ScaleSize( size.x ) / refImage.GetSize().x;
1477 refImage.SetImageScale( scaleFactor );
1478
1479 // TODO: support non-90-deg angles
1480 bitmap->Rotate( kstart, EDA_ANGLE( angle, DEGREES_T ) );
1481
1482 if( flipped )
1483 {
1484 int x = bitmap->GetPosition().x;
1485 MIRROR( x, KiROUND( kstart.x ) );
1486 bitmap->SetX( x );
1487
1488 refImage.MutableImage().Mirror( FLIP_DIRECTION::LEFT_RIGHT );
1489 }
1490
1491 aBoard->Add( bitmap.release(), ADD_MODE::APPEND );
1492 }
1493 }
1494 }
1495 else if( type == wxS( "STRING" ) )
1496 {
1497 wxString uuid = line.at( 1 );
1498
1499 // if( line.at( 2 ).is_number() )
1500 // int unk = line.at( 2 ).get<int>();
1501 // else if( line.at( 2 ).is_string() )
1502 // int unk = wxAtoi( line.at( 2 ).get<wxString>() );
1503
1504 int layer = line.at( 3 ).get<int>();
1505 PCB_LAYER_ID klayer = LayerToKi( layer );
1506
1507 VECTOR2D location( line.at( 4 ), line.at( 5 ) );
1508 wxString string = line.at( 6 );
1509 wxString font = line.at( 7 );
1510
1511 double height = line.at( 8 );
1512 double strokew = line.at( 9 );
1513
1514 int align = line.at( 12 );
1515 double angle = line.at( 13 );
1516 int inverted = line.at( 14 );
1517 int mirror = line.at( 16 );
1518
1519 PCB_TEXT* text = new PCB_TEXT( aBoard );
1520
1521 text->SetText( string );
1522 text->SetLayer( klayer );
1523 text->SetPosition( ScalePos( location ) );
1524 text->SetIsKnockout( inverted );
1525 text->SetTextThickness( ScaleSize( strokew ) );
1526 text->SetTextSize( VECTOR2D( ScaleSize( height * 0.6 ), ScaleSize( height * 0.7 ) ) );
1527
1528 if( font != wxS( "default" ) )
1529 {
1530 text->SetFont( KIFONT::FONT::GetFont( font ) );
1531 //text->SetupRenderCache( text->GetShownText(), text->GetFont(), EDA_ANGLE( angle, DEGREES_T ) );
1532
1533 //text->AddRenderCacheGlyph();
1534 // TODO: import geometry cache
1535 }
1536
1537 AlignText( text, align );
1538
1539 if( IsBackLayer( klayer ) ^ !!mirror )
1540 {
1541 text->SetMirrored( true );
1542 text->SetTextAngleDegrees( -angle );
1543 }
1544 else
1545 {
1546 text->SetTextAngleDegrees( angle );
1547 }
1548
1549 aBoard->Add( text, ADD_MODE::APPEND );
1550 }
1551 else if( type == wxS( "COMPONENT" ) )
1552 {
1553 wxString compId = line.at( 1 );
1554 componentLines[compId].push_back( line );
1555 }
1556 else if( type == wxS( "ATTR" ) )
1557 {
1558 wxString compId = line.at( 3 );
1559 componentLines[compId].push_back( line );
1560 }
1561 else if( type == wxS( "PAD_NET" ) )
1562 {
1563 wxString compId = line.at( 1 );
1564 componentLines[compId].push_back( line );
1565 }
1566 }
1567
1568 for( auto const& [compId, lines] : componentLines )
1569 {
1570 wxString deviceId;
1571 wxString fpIdOverride;
1572 wxString fpDesignator;
1573 std::map<wxString, wxString> localCompAttribs;
1574
1575 for( auto& line : lines )
1576 {
1577 if( line.size() == 0 )
1578 continue;
1579
1580 wxString type = line.at( 0 );
1581
1582 if( type == wxS( "COMPONENT" ) )
1583 {
1584 localCompAttribs = line.at( 7 );
1585 }
1586 else if( type == wxS( "ATTR" ) )
1587 {
1588 EASYEDAPRO::PCB_ATTR attr = line;
1589
1590 if( attr.key == wxS( "Device" ) )
1591 deviceId = attr.value;
1592
1593 else if( attr.key == wxS( "Footprint" ) )
1594 fpIdOverride = attr.value;
1595
1596 else if( attr.key == wxS( "Designator" ) )
1597 fpDesignator = attr.value;
1598 }
1599 }
1600
1601 if( deviceId.empty() )
1602 continue;
1603
1604 nlohmann::json compAttrs = aProject.at( "devices" ).at( deviceId ).at( "attributes" );
1605
1606 wxString fpId;
1607
1608 if( !fpIdOverride.IsEmpty() )
1609 fpId = fpIdOverride;
1610 else
1611 fpId = compAttrs.at( "Footprint" ).get<wxString>();
1612
1613 auto it = aFootprintMap.find( fpId );
1614 if( it == aFootprintMap.end() )
1615 {
1616 wxLogError( "Footprint of '%s' with uuid '%s' not found.", fpDesignator, fpId );
1617 continue;
1618 }
1619
1620 std::unique_ptr<FOOTPRINT>& footprintOrig = it->second;
1621 std::unique_ptr<FOOTPRINT> footprint( static_cast<FOOTPRINT*>( footprintOrig->Clone() ) );
1622
1623 wxString modelUuid, modelTitle, modelTransform;
1624
1625 if( auto val = get_opt( localCompAttribs, "3D Model" ) )
1626 modelUuid = *val;
1627 else
1628 modelUuid = compAttrs.value<wxString>( "3D Model", "" );
1629
1630 if( auto val = get_opt( localCompAttribs, "3D Model Title" ) )
1631 modelTitle = val->Trim();
1632 else
1633 modelTitle = compAttrs.value<wxString>( "3D Model Title", modelUuid ).Trim();
1634
1635 if( auto val = get_opt( localCompAttribs, "3D Model Transform" ) )
1636 modelTransform = *val;
1637 else
1638 modelTransform = compAttrs.value<wxString>( "3D Model Transform", "" );
1639
1640 fillFootprintModelInfo( footprint.get(), modelUuid, modelTitle, modelTransform );
1641
1642 footprint->SetParent( aBoard );
1643
1644 for( auto& line : lines )
1645 {
1646 if( line.size() == 0 )
1647 continue;
1648
1649 wxString type = line.at( 0 );
1650
1651 if( type == wxS( "COMPONENT" ) )
1652 {
1653 int layer = line.at( 3 );
1654 PCB_LAYER_ID klayer = LayerToKi( layer );
1655
1656 VECTOR2D center( line.at( 4 ), line.at( 5 ) );
1657
1658 double orient = line.at( 6 );
1659 //std::map<wxString, wxString> props = line.at( 7 );
1660
1661 if( klayer == B_Cu )
1662 footprint->Flip( footprint->GetPosition(), FLIP_DIRECTION::TOP_BOTTOM );
1663
1664 footprint->SetOrientationDegrees( orient );
1665 footprint->SetPosition( ScalePos( center ) );
1666 }
1667 else if( type == wxS( "ATTR" ) )
1668 {
1669 EASYEDAPRO::PCB_ATTR attr = line;
1670
1671 PCB_LAYER_ID klayer = LayerToKi( attr.layer );
1672
1673 PCB_TEXT* text = nullptr;
1674 bool add = false;
1675
1676 if( attr.key == wxS( "Designator" ) )
1677 {
1678 if( attr.key == wxS( "Designator" ) )
1679 {
1680 text = footprint->GetField( REFERENCE_FIELD );
1681 }
1682 else
1683 {
1684 text = new PCB_TEXT( footprint.get() );
1685 add = true;
1686 }
1687
1688 if( attr.fontName != wxS( "default" ) )
1689 text->SetFont( KIFONT::FONT::GetFont( attr.fontName ) );
1690
1691 if( attr.valVisible && attr.keyVisible )
1692 {
1693 text->SetText( attr.key + ':' + attr.value );
1694 }
1695 else if( attr.keyVisible )
1696 {
1697 text->SetText( attr.key );
1698 }
1699 else
1700 {
1701 text->SetText( attr.value );
1702 }
1703
1704 text->SetVisible( attr.keyVisible || attr.valVisible );
1705 text->SetLayer( klayer );
1706 text->SetPosition( ScalePos( attr.position ) );
1707 text->SetTextAngleDegrees( footprint->IsFlipped() ? -attr.rotation
1708 : attr.rotation );
1709 text->SetIsKnockout( attr.inverted );
1710 text->SetTextThickness( ScaleSize( attr.strokeWidth ) );
1711 text->SetTextSize( VECTOR2D( ScaleSize( attr.height * 0.55 ),
1712 ScaleSize( attr.height * 0.6 ) ) );
1713
1714 AlignText( text, attr.textOrigin );
1715
1716 if( add )
1717 footprint->Add( text, ADD_MODE::APPEND );
1718 }
1719 }
1720 else if( type == wxS( "PAD_NET" ) )
1721 {
1722 wxString padNumber = line.at( 2 );
1723 wxString padNet = line.at( 3 );
1724
1725 PAD* pad = footprint->FindPadByNumber( padNumber );
1726 if( pad )
1727 {
1728 pad->SetNet( aBoard->FindNet( padNet ) );
1729 }
1730 else
1731 {
1732 // Not a pad
1733 }
1734 }
1735 }
1736
1737 aBoard->Add( footprint.release(), ADD_MODE::APPEND );
1738 }
1739
1740 // Set zone fills
1742 {
1743 for( auto& [uuid, zone] : poursToFill )
1744 {
1745 SHAPE_POLY_SET fillPolySet;
1746 SHAPE_POLY_SET thermalSpokes;
1747
1748 auto range = boardPouredMap.equal_range( uuid );
1749 for( auto& it = range.first; it != range.second; ++it )
1750 {
1751 const EASYEDAPRO::POURED& poured = it->second;
1752 int unki = poured.unki;
1753
1754 SHAPE_POLY_SET thisPoly;
1755
1756 for( int dataId = 0; dataId < poured.polyData.size(); dataId++ )
1757 {
1758 const nlohmann::json& fillData = poured.polyData[dataId];
1759 const double ptScale = 10;
1760
1761 SHAPE_LINE_CHAIN contour =
1762 ParseContour( fillData, false, ARC_HIGH_DEF / ptScale );
1763
1764 // Scale the fill
1765 for( int i = 0; i < contour.PointCount(); i++ )
1766 contour.SetPoint( i, contour.GetPoint( i ) * ptScale );
1767
1768 if( poured.isPoly )
1769 {
1770 contour.SetClosed( true );
1771
1772 // The contour can be self-intersecting
1773 SHAPE_POLY_SET simple( contour );
1775
1776 if( dataId == 0 )
1777 {
1778 thisPoly.Append( simple );
1779 }
1780 else
1781 {
1783 }
1784 }
1785 else
1786 {
1787 const int thermalWidth = pcbIUScale.mmToIU( 0.2 ); // Generic
1788
1789 for( int segId = 0; segId < contour.SegmentCount(); segId++ )
1790 {
1791 const SEG& seg = contour.CSegment( segId );
1792
1793 TransformOvalToPolygon( thermalSpokes, seg.A, seg.B, thermalWidth,
1795 }
1796 }
1797 }
1798
1799 fillPolySet.Append( thisPoly );
1800 }
1801
1802 if( !fillPolySet.IsEmpty() )
1803 {
1805
1806 const int strokeWidth = pcbIUScale.MilsToIU( 8 ); // Seems to be 8 mils
1807
1808 fillPolySet.Inflate( strokeWidth / 2, CORNER_STRATEGY::ROUND_ALL_CORNERS,
1809 ARC_HIGH_DEF, false );
1810
1811 fillPolySet.BooleanAdd( thermalSpokes, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
1812
1814
1815 zone->SetFilledPolysList( zone->GetFirstLayer(), fillPolySet );
1816 zone->SetNeedRefill( false );
1817 zone->SetIsFilled( true );
1818 }
1819 }
1820 }
1821
1822 // Heal board outlines
1823 std::vector<PCB_SHAPE*> shapes;
1824 std::vector<std::unique_ptr<PCB_SHAPE>> newShapes;
1825
1826 for( BOARD_ITEM* item : aBoard->Drawings() )
1827 {
1828 if( !item->IsOnLayer( Edge_Cuts ) )
1829 continue;
1830
1831 if( item->Type() == PCB_SHAPE_T )
1832 shapes.push_back( static_cast<PCB_SHAPE*>( item ) );
1833 }
1834
1835 ConnectBoardShapes( shapes, newShapes, SHAPE_JOIN_DISTANCE );
1836
1837 for( std::unique_ptr<PCB_SHAPE>& ptr : newShapes )
1838 aBoard->Add( ptr.release(), ADD_MODE::APPEND );
1839
1840 // Center the board
1841 BOX2I outlineBbox = aBoard->ComputeBoundingBox( true );
1842 PAGE_INFO pageInfo = aBoard->GetPageSettings();
1843
1844 VECTOR2D pageCenter( pcbIUScale.MilsToIU( pageInfo.GetWidthMils() / 2 ),
1845 pcbIUScale.MilsToIU( pageInfo.GetHeightMils() / 2 ) );
1846
1847 VECTOR2D offset = pageCenter - outlineBbox.GetCenter();
1848
1849 int alignGrid = pcbIUScale.mmToIU( 10 );
1850 offset.x = KiROUND( offset.x / alignGrid ) * alignGrid;
1851 offset.y = KiROUND( offset.y / alignGrid ) * alignGrid;
1852
1853 aBoard->Move( offset );
1854 bds.SetAuxOrigin( offset );
1855}
@ 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:115
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 SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:288
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:290
LSET GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition: board.cpp:773
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition: board.cpp:998
void SetEnabledLayers(LSET aLayerMask)
A proxy function that calls the correspondent function in m_BoardSettings.
Definition: board.cpp:793
const PAGE_INFO & GetPageSettings() const
Definition: board.h:689
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition: board.cpp:1916
bool SetLayerName(PCB_LAYER_ID aLayer, const wxString &aLayerName)
Changes the name of the layer given by aLayer.
Definition: board.cpp:593
void Move(const VECTOR2I &aMoveVector) override
Move this object.
Definition: board.cpp:500
BOX2I ComputeBoundingBox(bool aBoardEdgesOnly=false) const
Calculate the bounding box containing all board items (or board edge segments).
Definition: board.cpp:1668
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:890
unsigned GetNetCount() const
Definition: board.h:902
const DRAWINGS & Drawings() const
Definition: board.h:333
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:79
virtual void SetVisible(bool aVisible)
Definition: eda_text.cpp:275
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:182
int GetFieldCount() const
Return the number of fields in this symbol.
Definition: footprint.h:720
PCB_FIELD * GetFieldByName(const wxString &aFieldName)
Return a field in this symbol.
Definition: footprint.cpp:552
PCB_FIELD * AddField(const PCB_FIELD &aField)
Add a field to the symbol.
Definition: footprint.cpp:594
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition: footprint.cpp:982
std::vector< FP_3DMODEL > & Models()
Definition: footprint.h:220
PCB_FIELDS & Fields()
Definition: footprint.h:203
PCB_FIELD * GetField(MANDATORY_FIELD_T aFieldType)
Return a mandatory field in this symbol.
Definition: footprint.cpp:518
DRAWINGS & GraphicalItems()
Definition: footprint.h:209
VECTOR3D m_Offset
3D model offset (mm)
Definition: footprint.h:101
VECTOR3D m_Rotation
3D model rotation (degrees)
Definition: footprint.h:100
wxString m_Filename
The 3D shape filename in 3D library.
Definition: footprint.h:103
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:146
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:49
LSET is a set of PCB_LAYER_IDs.
Definition: lset.h:36
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:138
Definition: pad.h:54
static LSET PTHMask()
layer set for a through hole pad
Definition: pad.cpp:267
static LSET SMDMask()
layer set for a SMD pad on Front layer
Definition: pad.cpp:274
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
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:212
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 BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset difference For aFastMode meaning, see function booleanOp.
void Fracture(POLYGON_MODE aFastMode)
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
void BooleanAdd(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset union For aFastMode meaning, see function booleanOp.
void Inflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, bool aSimplify=false)
Perform outline inflation/deflation.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
std::vector< SHAPE_LINE_CHAIN > POLYGON
represents a single polygon outline with holes.
void Simplify(POLYGON_MODE aFastMode)
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections) For aFastMo...
void RebuildHolesFromContours()
Extract all contours from this polygon set, then recreate polygons with holes.
int OutlineCount() const
Return the number of outlines in the set.
const std::vector< POLYGON > & CPolygons() const
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
const SHAPE_LINE_CHAIN Outline() const
Definition: shape_rect.h: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:645
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".
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:691
VECTOR2< double > VECTOR2D
Definition: vector2d.h:690