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 // 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->GetFields() )
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
883 polySet.Simplify();
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();
1161 zoneFillPoly.Fracture();
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 );
1774 simple.Simplify();
1775
1776 if( dataId == 0 )
1777 {
1778 thisPoly.Append( simple );
1779 }
1780 else
1781 {
1782 thisPoly.BooleanSubtract( simple );
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 {
1804 fillPolySet.Simplify();
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 );
1812
1813 fillPolySet.Fracture();
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: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 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:817
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition: board.cpp:1042
void SetEnabledLayers(LSET aLayerMask)
A proxy function that calls the correspondent function in m_BoardSettings.
Definition: board.cpp:837
const PAGE_INFO & GetPageSettings() const
Definition: board.h:697
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition: board.cpp:1961
bool SetLayerName(PCB_LAYER_ID aLayer, const wxString &aLayerName)
Changes the name of the layer given by aLayer.
Definition: board.cpp:631
void Move(const VECTOR2I &aMoveVector) override
Move this object.
Definition: board.cpp:502
BOX2I ComputeBoundingBox(bool aBoardEdgesOnly=false) const
Calculate the bounding box containing all board items (or board edge segments).
Definition: board.cpp:1713
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:934
unsigned GetNetCount() const
Definition: board.h:910
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
virtual void SetVisible(bool aVisible)
Definition: eda_text.cpp:377
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:268
PCB_FIELD * GetFieldByName(const wxString &aFieldName)
Return a field in this symbol.
Definition: footprint.cpp:615
PCB_FIELD * AddField(const PCB_FIELD &aField)
Add a field to the symbol.
Definition: footprint.cpp:673
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:1079
void GetFields(std::vector< PCB_FIELD * > &aVector, bool aVisibleOnly) const
Populate a std::vector with PCB_TEXTs.
Definition: footprint.cpp:667
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:575
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: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: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
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:705
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:695
VECTOR2< double > VECTOR2D
Definition: vector2d.h:694