KiCad PCB EDA Suite
Loading...
Searching...
No Matches
sch_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-2024 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 <core/map_helpers.h>
29
30#include <sch_io/sch_io_mgr.h>
31#include <schematic.h>
32#include <sch_sheet.h>
33#include <sch_line.h>
34#include <sch_bitmap.h>
35#include <sch_no_connect.h>
36#include <sch_label.h>
37#include <sch_junction.h>
38#include <sch_edit_frame.h>
39#include <sch_shape.h>
40#include <string_utils.h>
41#include <bezier_curves.h>
42#include <wx/base64.h>
43#include <wx/log.h>
44#include <wx/url.h>
45#include <wx/mstream.h>
46#include <gfx_import_utils.h>
50
51
52// clang-format off
53static const std::vector<wxString> c_attributesWhitelist = { "Value",
54 "Datasheet",
55 "Manufacturer Part",
56 "Manufacturer",
57 "BOM_Manufacturer Part",
58 "BOM_Manufacturer",
59 "Supplier Part",
60 "Supplier",
61 "BOM_Supplier Part",
62 "BOM_Supplier",
63 "LCSC Part Name" };
64// clang-format on
65
66
68 PROGRESS_REPORTER* aProgressReporter )
69{
70 m_schematic = aSchematic;
71}
72
73
75{
76}
77
78
79double SCH_EASYEDAPRO_PARSER::Convert( wxString aValue )
80{
81 double value = 0;
82
83 if( !aValue.ToCDouble( &value ) )
84 THROW_IO_ERROR( wxString::Format( _( "Failed to parse value: '%s'" ), aValue ) );
85
86 return value;
87}
88
89
90double SCH_EASYEDAPRO_PARSER::SizeToKi( wxString aValue )
91{
92 return ScaleSize( Convert( aValue ) );
93}
94
95
96static LINE_STYLE ConvertStrokeStyle( int aStyle )
97{
98 if( aStyle == 0 )
99 return LINE_STYLE::SOLID;
100 else if( aStyle == 1 )
101 return LINE_STYLE::DASH;
102 else if( aStyle == 2 )
103 return LINE_STYLE::DOT;
104 else if( aStyle == 3 )
105 return LINE_STYLE::DASHDOT;
106
107 return LINE_STYLE::DEFAULT;
108}
109
110
111template <typename T>
112void SCH_EASYEDAPRO_PARSER::ApplyFontStyle( const std::map<wxString, nlohmann::json>& fontStyles,
113 T& text, const wxString& styleStr )
114{
115 auto it = fontStyles.find( styleStr );
116
117 if( it == fontStyles.end() )
118 return;
119
120 nlohmann::json style = it->second;
121
122 if( !style.is_array() )
123 return;
124
125 if( style.size() < 12 )
126 return;
127
128 if( style.at( 3 ).is_string() )
129 {
130 COLOR4D color( style.at( 3 ).get<wxString>() );
131 text->SetTextColor( color );
132 }
133
134 if( style.at( 4 ).is_string() )
135 {
136 wxString fontname = ( style.at( 4 ) );
137
138 if( !fontname.IsSameAs( wxS( "default" ), false ) )
139 text->SetFont( KIFONT::FONT::GetFont( fontname ) );
140 }
141
142 if( style.at( 5 ).is_number() )
143 {
144 double size = style.at( 5 ).get<double>() * 0.5;
145 text->SetTextSize( VECTOR2I( ScaleSize( size ), ScaleSize( size ) ) );
146 }
147
148 if( style.at( 10 ).is_number() )
149 {
150 int valign = style.at( 10 );
151
152 if( !text->GetText().Contains( wxS( "\n" ) ) )
153 {
154 if( valign == 0 )
155 text->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
156 else if( valign == 1 )
157 text->SetVertJustify( GR_TEXT_V_ALIGN_CENTER );
158 else if( valign == 2 )
159 text->SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM );
160 }
161 else
162 {
163 text->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
164 // TODO: align by first line
165 }
166 }
167 else
168 {
169 text->SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM );
170 }
171
172 if( style.at( 11 ).is_number() )
173 {
174 int halign = style.at( 11 );
175
176 if( halign == 0 )
177 text->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
178 else if( halign == 1 )
179 text->SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
180 else if( halign == 2 )
181 text->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
182 }
183 else
184 {
185 text->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
186 }
187}
188
189
190template <typename T>
191void SCH_EASYEDAPRO_PARSER::ApplyLineStyle( const std::map<wxString, nlohmann::json>& lineStyles,
192 T& shape, const wxString& styleStr )
193{
194 auto it = lineStyles.find( styleStr );
195
196 if( it == lineStyles.end() )
197 return;
198
199 nlohmann::json style = it->second;
200
201 if( !style.is_array() )
202 return;
203
204 if( style.size() < 6 )
205 return;
206
207 STROKE_PARAMS stroke = shape->GetStroke();
208
209 if( style.at( 2 ).is_string() )
210 {
211 wxString colorStr = style.at( 2 ).get<wxString>();
212
213 if( !colorStr.empty() && colorStr.starts_with( wxS( "#" ) ) )
214 {
215 COLOR4D color( colorStr );
216 stroke.SetColor( color );
217 }
218 }
219
220 if( style.at( 3 ).is_number() )
221 {
222 int dashStyle = style.at( 3 );
223 stroke.SetLineStyle( ConvertStrokeStyle( dashStyle ) );
224 }
225
226 if( style.at( 5 ).is_number() )
227 {
228 double thickness = style.at( 5 );
229 stroke.SetWidth( ScaleSize( thickness ) );
230 }
231
232 shape->SetStroke( stroke );
233}
234
235
237 const wxString aInput, const std::map<wxString, wxString>& aDeviceAttributes )
238{
239 wxString inputText = aInput;
240 wxString resolvedText;
241 int variableCount = 0;
242
243 // Resolve variables
244 // ={Variable1}text{Variable2}
245 do
246 {
247 if( !inputText.StartsWith( wxS( "={" ) ) )
248 return inputText;
249
250 resolvedText.Clear();
251 variableCount = 0;
252
253 for( size_t i = 1; i < inputText.size(); )
254 {
255 wxUniChar c = inputText[i++];
256
257 if( c == '{' )
258 {
259 wxString varName;
260 bool endFound = false;
261
262 while( i < inputText.size() )
263 {
264 c = inputText[i++];
265
266 if( c == '}' )
267 {
268 endFound = true;
269 break;
270 }
271
272 varName << c;
273 }
274
275 if( !endFound )
276 return inputText;
277
278 wxString varValue =
279 get_def( aDeviceAttributes, varName, wxString::Format( "{%s!}", varName ) );
280
281 resolvedText << varValue;
282 variableCount++;
283 }
284 else
285 {
286 resolvedText << c;
287 }
288 }
289 inputText = resolvedText;
290
291 } while( variableCount > 0 );
292
293 return resolvedText;
294}
295
296
297template <typename T>
298void SCH_EASYEDAPRO_PARSER::ApplyAttrToField( const std::map<wxString, nlohmann::json>& fontStyles,
299 T* field, const EASYEDAPRO::SCH_ATTR& aAttr,
300 bool aIsSym, bool aToSym,
301 const std::map<wxString, wxString>& aDeviceAttributes,
302 SCH_SYMBOL* aParent )
303{
304 EDA_TEXT* text = static_cast<EDA_TEXT*>( field );
305
306 text->SetText( ResolveFieldVariables( aAttr.value, aDeviceAttributes ) );
307 text->SetVisible( aAttr.keyVisible || aAttr.valVisible );
308
309 field->SetNameShown( aAttr.keyVisible );
310
311 if( aAttr.position )
312 {
313 field->SetPosition( !aIsSym ? ScalePos( *aAttr.position )
314 : ScalePosSym( *aAttr.position ) );
315 }
316
317 ApplyFontStyle( fontStyles, text, aAttr.fontStyle );
318
319 auto parent = aParent;
320 if( parent && parent->Type() == SCH_SYMBOL_T )
321 {
322 int orient = static_cast<SCH_SYMBOL*>( parent )->GetOrientation();
323
324 if( orient == SYM_ORIENT_180 )
325 {
326 text->SetVertJustify( static_cast<GR_TEXT_V_ALIGN_T>( -text->GetVertJustify() ) );
327 text->SetHorizJustify( static_cast<GR_TEXT_H_ALIGN_T>( -text->GetHorizJustify() ) );
328 }
329 else if( orient == SYM_MIRROR_X + SYM_ORIENT_0 )
330 {
331 text->SetVertJustify( static_cast<GR_TEXT_V_ALIGN_T>( -text->GetVertJustify() ) );
332 }
333 else if( orient == SYM_MIRROR_Y + SYM_ORIENT_0 )
334 {
335 text->SetHorizJustify( static_cast<GR_TEXT_H_ALIGN_T>( -text->GetHorizJustify() ) );
336 }
337 else if( orient == SYM_MIRROR_Y + SYM_ORIENT_180 )
338 {
339 text->SetHorizJustify( static_cast<GR_TEXT_H_ALIGN_T>( text->GetHorizJustify() ) );
340 }
341 else if( orient == SYM_ORIENT_90 )
342 {
343 text->SetTextAngle( ANGLE_VERTICAL );
344 text->SetVertJustify( static_cast<GR_TEXT_V_ALIGN_T>( -text->GetVertJustify() ) );
345 text->SetHorizJustify( static_cast<GR_TEXT_H_ALIGN_T>( -text->GetHorizJustify() ) );
346 }
347 if( orient == SYM_ORIENT_270 )
348 {
349 text->SetTextAngle( ANGLE_VERTICAL );
350 }
351 else if( orient == SYM_MIRROR_X + SYM_ORIENT_90 )
352 {
353 text->SetTextAngle( ANGLE_VERTICAL );
354 text->SetVertJustify( static_cast<GR_TEXT_V_ALIGN_T>( -text->GetVertJustify() ) );
355 text->SetHorizJustify( static_cast<GR_TEXT_H_ALIGN_T>( -text->GetHorizJustify() ) );
356 }
357 else if( orient == SYM_MIRROR_X + SYM_ORIENT_270 )
358 {
359 text->SetTextAngle( ANGLE_VERTICAL );
360 text->SetVertJustify( static_cast<GR_TEXT_V_ALIGN_T>( -text->GetVertJustify() ) );
361 }
362 else if( orient == SYM_MIRROR_Y + SYM_ORIENT_90 )
363 {
364 text->SetTextAngle( ANGLE_VERTICAL );
365 text->SetHorizJustify( static_cast<GR_TEXT_H_ALIGN_T>( -text->GetHorizJustify() ) );
366 }
367 else if( orient == SYM_MIRROR_Y + SYM_ORIENT_270 )
368 {
369 text->SetHorizJustify( static_cast<GR_TEXT_H_ALIGN_T>( text->GetHorizJustify() ) );
370 }
371
372 if( aAttr.rotation == 90 )
373 {
374 if( text->GetTextAngle() == ANGLE_HORIZONTAL )
375 text->SetTextAngle( ANGLE_VERTICAL );
376 else
377 text->SetTextAngle( ANGLE_HORIZONTAL );
378
379 if( orient == SYM_ORIENT_90 )
380 {
381 text->SetVertJustify( static_cast<GR_TEXT_V_ALIGN_T>( -text->GetVertJustify() ) );
382 text->SetHorizJustify( static_cast<GR_TEXT_H_ALIGN_T>( -text->GetHorizJustify() ) );
383 }
384 if( orient == SYM_ORIENT_270 )
385 {
386 text->SetVertJustify( static_cast<GR_TEXT_V_ALIGN_T>( -text->GetVertJustify() ) );
387 text->SetHorizJustify( static_cast<GR_TEXT_H_ALIGN_T>( -text->GetHorizJustify() ) );
388 }
389 else if( orient == SYM_MIRROR_X + SYM_ORIENT_90 )
390 {
391 text->SetVertJustify( static_cast<GR_TEXT_V_ALIGN_T>( -text->GetVertJustify() ) );
392 }
393 }
394 }
395}
396
397
399SCH_EASYEDAPRO_PARSER::ParseSymbol( const std::vector<nlohmann::json>& aLines,
400 const std::map<wxString, wxString>& aDeviceAttributes )
401{
402 EASYEDAPRO::SYM_INFO symInfo;
403
404 std::unique_ptr<LIB_SYMBOL> ksymbolPtr = std::make_unique<LIB_SYMBOL>( wxEmptyString );
405 LIB_SYMBOL* ksymbol = ksymbolPtr.get();
406
407 std::map<wxString, nlohmann::json> lineStyles;
408 std::map<wxString, nlohmann::json> fontStyles;
409 std::map<wxString, int> partUnits;
410
411 std::map<int, std::map<wxString, EASYEDAPRO::SCH_ATTR>> unitAttributes;
412 std::map<int, std::map<wxString, std::vector<nlohmann::json>>> unitParentedLines;
413
414 int totalUnits = 0;
415
416 for( const nlohmann::json& line : aLines )
417 {
418 wxString type = line.at( 0 );
419
420 if( type == wxS( "LINESTYLE" ) )
421 lineStyles[line.at( 1 )] = line;
422 else if( type == wxS( "FONTSTYLE" ) )
423 fontStyles[line.at( 1 )] = line;
424 else if( type == wxS( "PART" ) )
425 partUnits[line.at( 1 )] = ++totalUnits;
426 }
427
428 symInfo.partUnits = partUnits;
429 ksymbol->SetUnitCount( totalUnits, false );
430
431 int currentUnit = 1;
432
433 for( const nlohmann::json& line : aLines )
434 {
435 wxString type = line.at( 0 );
436
437 if( type == wxS( "PART" ) )
438 {
439 currentUnit = partUnits.at( line.at( 1 ) );
440 }
441 else if( type == wxS( "RECT" ) )
442 {
443 VECTOR2D start( line.at( 2 ), line.at( 3 ) );
444 VECTOR2D end( line.at( 4 ), line.at( 5 ) );
445 wxString styleStr = line.at( 9 );
446
447 auto rect = std::make_unique<SCH_SHAPE>( SHAPE_T::RECTANGLE, LAYER_DEVICE );
448
449 rect->SetStart( ScalePosSym( start ) );
450 rect->SetEnd( ScalePosSym( end ) );
451
452 rect->SetUnit( currentUnit );
453 ApplyLineStyle( lineStyles, rect, styleStr );
454
455 ksymbol->AddDrawItem( rect.release() );
456 }
457 else if( type == wxS( "CIRCLE" ) )
458 {
459 VECTOR2D center( line.at( 2 ), line.at( 3 ) );
460 double radius = line.at( 4 );
461 wxString styleStr = line.at( 5 );
462
463 auto circle = std::make_unique<SCH_SHAPE>( SHAPE_T::CIRCLE, LAYER_DEVICE );
464
465 circle->SetCenter( ScalePosSym( center ) );
466 circle->SetEnd( circle->GetCenter() + VECTOR2I( ScaleSize( radius ), 0 ) );
467
468 circle->SetUnit( currentUnit );
469 ApplyLineStyle( lineStyles, circle, styleStr );
470
471 ksymbol->AddDrawItem( circle.release() );
472 }
473 else if( type == wxS( "ARC" ) )
474 {
475 VECTOR2D start( line.at( 2 ), line.at( 3 ) );
476 VECTOR2D mid( line.at( 4 ), line.at( 5 ) );
477 VECTOR2D end( line.at( 6 ), line.at( 7 ) );
478 wxString styleStr = line.at( 8 );
479
480 VECTOR2D kstart = ScalePosSym( start );
481 VECTOR2D kmid = ScalePosSym( mid );
482 VECTOR2D kend = ScalePosSym( end );
483
484 auto shape = std::make_unique<SCH_SHAPE>( SHAPE_T::ARC, LAYER_DEVICE );
485
486 shape->SetArcGeometry( kstart, kmid, kend );
487
488 shape->SetUnit( currentUnit );
489 ApplyLineStyle( lineStyles, shape, styleStr );
490
491 ksymbol->AddDrawItem( shape.release() );
492 }
493 else if( type == wxS( "BEZIER" ) )
494 {
495 std::vector<double> points = line.at( 2 );
496 wxString styleStr = line.at( 3 );
497
498 auto shape = std::make_unique<SCH_SHAPE>( SHAPE_T::BEZIER, LAYER_DEVICE );
499
500 for( size_t i = 1; i < points.size(); i += 2 )
501 {
502 VECTOR2I pt = ScalePosSym( VECTOR2D( points[i - 1], points[i] ) );
503
504 switch( i )
505 {
506 case 1: shape->SetStart( pt ); break;
507 case 3: shape->SetBezierC1( pt ); break;
508 case 5: shape->SetBezierC2( pt ); break;
509 case 7: shape->SetEnd( pt ); break;
510 }
511 }
512
513 shape->SetUnit( currentUnit );
514 ApplyLineStyle( lineStyles, shape, styleStr );
515
516 ksymbol->AddDrawItem( shape.release() );
517 }
518 else if( type == wxS( "POLY" ) )
519 {
520 std::vector<double> points = line.at( 2 );
521 wxString styleStr = line.at( 4 );
522
523 auto shape = std::make_unique<SCH_SHAPE>( SHAPE_T::POLY, LAYER_DEVICE );
524
525 for( size_t i = 1; i < points.size(); i += 2 )
526 shape->AddPoint( ScalePosSym( VECTOR2D( points[i - 1], points[i] ) ) );
527
528 shape->SetUnit( currentUnit );
529 ApplyLineStyle( lineStyles, shape, styleStr );
530
531 ksymbol->AddDrawItem( shape.release() );
532 }
533 else if( type == wxS( "TEXT" ) )
534 {
535 VECTOR2D pos( line.at( 2 ), line.at( 3 ) );
536 double angle = line.at( 4 );
537 wxString textStr = line.at( 5 );
538 wxString fontStyleStr = line.at( 6 );
539
540 auto text = std::make_unique<SCH_TEXT>( ScalePosSym( pos ), UnescapeHTML( textStr ),
541 LAYER_DEVICE );
542
543 text->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
544 text->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
545 text->SetTextAngleDegrees( angle );
546
547 text->SetUnit( currentUnit );
548 ApplyFontStyle( fontStyles, text, fontStyleStr );
549
550 ksymbol->AddDrawItem( text.release() );
551 }
552 else if( type == wxS( "OBJ" ) )
553 {
554 VECTOR2D start, size;
555 wxString mimeType, data;
556 //double angle = 0;
557 int upsideDown = 0;
558
559 if( line.at( 3 ).is_number() )
560 {
561 start = VECTOR2D( line.at( 3 ), line.at( 4 ) );
562 size = VECTOR2D( line.at( 5 ), line.at( 6 ) );
563 //angle = line.at( 7 );
564 upsideDown = line.at( 8 );
565
566 wxString imageUrl = line.at( 9 );
567
568 if( imageUrl.BeforeFirst( ':' ) == wxS( "data" ) )
569 {
570 wxArrayString paramsArr =
571 wxSplit( imageUrl.AfterFirst( ':' ).BeforeFirst( ',' ), ';', '\0' );
572
573 data = imageUrl.AfterFirst( ',' );
574
575 if( paramsArr.size() > 0 )
576 {
577 mimeType = paramsArr[0];
578 }
579 }
580 }
581 else if( line.at( 3 ).is_string() )
582 {
583 mimeType = line.at( 3 ).get<wxString>().BeforeFirst( ';' );
584
585 start = VECTOR2D( line.at( 4 ), line.at( 5 ) );
586 size = VECTOR2D( line.at( 6 ), line.at( 7 ) );
587 //angle = line.at( 8 );
588 data = line.at( 9 ).get<wxString>();
589 }
590
591 if( mimeType.empty() || data.empty() )
592 continue;
593
594 wxMemoryBuffer buf = wxBase64Decode( data );
595
596 if( mimeType == wxS( "image/svg+xml" ) )
597 {
598 VECTOR2D offset = ScalePosSym( start );
599
600 SVG_IMPORT_PLUGIN svgImportPlugin;
601 GRAPHICS_IMPORTER_LIB_SYMBOL libsymImporter( ksymbol, 0 );
602
603 svgImportPlugin.SetImporter( &libsymImporter );
604 svgImportPlugin.LoadFromMemory( buf );
605
606 VECTOR2D imSize( svgImportPlugin.GetImageWidth(),
607 svgImportPlugin.GetImageHeight() );
608
609 VECTOR2D pixelScale( schIUScale.IUTomm( ScaleSize( size.x ) ) / imSize.x,
610 schIUScale.IUTomm( ScaleSize( size.y ) ) / imSize.y );
611
612 if( upsideDown )
613 pixelScale.y *= -1;
614
615 libsymImporter.SetScale( pixelScale );
616
617 VECTOR2D offsetMM( schIUScale.IUTomm( offset.x ), schIUScale.IUTomm( offset.y ) );
618
619 libsymImporter.SetImportOffsetMM( offsetMM );
620
621 svgImportPlugin.Import();
622
623 // TODO: rotation
624 for( std::unique_ptr<EDA_ITEM>& item : libsymImporter.GetItems() )
625 ksymbol->AddDrawItem( static_cast<SCH_ITEM*>( item.release() ) );
626 }
627 else
628 {
629 wxMemoryInputStream memis( buf.GetData(), buf.GetDataLen() );
630
631 wxImage::SetDefaultLoadFlags( wxImage::GetDefaultLoadFlags()
632 & ~wxImage::Load_Verbose );
633 wxImage img;
634 if( img.LoadFile( memis, mimeType ) )
635 {
636 int dimMul = img.GetWidth() * img.GetHeight();
637 double maxPixels = 30000;
638
639 if( dimMul > maxPixels )
640 {
641 double scale = sqrt( maxPixels / dimMul );
642 img.Rescale( img.GetWidth() * scale, img.GetHeight() * scale );
643 }
644
645 VECTOR2D pixelScale( ScaleSize( size.x ) / img.GetWidth(),
646 ScaleSize( size.y ) / img.GetHeight() );
647
648 // TODO: rotation
649 ConvertImageToLibShapes( ksymbol, 0, img, pixelScale, ScalePosSym( start ) );
650 }
651 }
652 }
653 else if( type == wxS( "HEAD" ) )
654 {
655 symInfo.head = line;
656 }
657 else if( type == wxS( "PIN" ) )
658 {
659 wxString pinId = line.at( 1 );
660 unitParentedLines[currentUnit][pinId].push_back( line );
661 }
662 else if( type == wxS( "ATTR" ) )
663 {
664 wxString parentId = line.at( 2 );
665
666 if( parentId.empty() )
667 {
668 EASYEDAPRO::SCH_ATTR attr = line;
669 unitAttributes[currentUnit].emplace( attr.key, attr );
670 }
671 else
672 {
673 unitParentedLines[currentUnit][parentId].push_back( line );
674 }
675 }
676 }
677
680 {
681 ksymbol->SetPower();
682 ksymbol->GetReferenceField().SetText( wxS( "#PWR" ) );
683 ksymbol->GetReferenceField().SetVisible( false );
684 ksymbol->SetKeyWords( wxS( "power-flag" ) );
685 ksymbol->SetShowPinNames( false );
686 ksymbol->SetShowPinNumbers( false );
687
688 if( auto globalNetAttr = get_opt( unitAttributes[1], wxS( "Global Net Name" ) ) )
689 {
690 ApplyAttrToField( fontStyles, &ksymbol->GetValueField(), *globalNetAttr, true, true );
691
692 wxString globalNetname = globalNetAttr->value;
693
694 if( !globalNetname.empty() )
695 {
696 ksymbol->SetDescription( wxString::Format(
697 _( "Power symbol creates a global label with name '%s'" ),
698 globalNetname ) );
699 }
700 }
701 }
702 else
703 {
704 auto designatorAttr = get_opt( unitAttributes[1], wxS( "Designator" ) );
705
706 if( designatorAttr && !designatorAttr->value.empty() )
707 {
708 wxString symbolPrefix = designatorAttr->value;
709
710 if( symbolPrefix.EndsWith( wxS( "?" ) ) )
711 symbolPrefix.RemoveLast();
712
713 ksymbol->GetReferenceField().SetText( symbolPrefix );
714 }
715
716 for( const wxString& attrName : c_attributesWhitelist )
717 {
718 if( auto valOpt = get_opt( aDeviceAttributes, attrName ) )
719 {
720 if( valOpt->empty() )
721 continue;
722
723 SCH_FIELD* fd = ksymbol->FindField( attrName, true );
724
725 if( !fd )
726 {
727 fd = new SCH_FIELD( ksymbol, ksymbol->GetNextAvailableFieldId(), attrName );
728 ksymbol->AddField( fd );
729 }
730
731 wxString value = *valOpt;
732
733 value.Replace( wxS( "\u2103" ), wxS( "\u00B0C" ), true ); // ℃ -> °C
734
735 fd->SetText( value );
736 fd->SetVisible( false );
737 }
738 }
739 }
740
741 for( auto& [unitId, parentedLines] : unitParentedLines )
742 {
743 for( auto& [pinId, lines] : parentedLines )
744 {
745 std::optional<EASYEDAPRO::SYM_PIN> epin;
746 std::map<wxString, EASYEDAPRO::SCH_ATTR> pinAttributes;
747
748 for( const nlohmann::json& line : lines )
749 {
750 wxString type = line.at( 0 );
751
752 if( type == wxS( "ATTR" ) )
753 {
754 EASYEDAPRO::SCH_ATTR attr = line;
755 pinAttributes.emplace( attr.key, attr );
756 }
757 else if( type == wxS( "PIN" ) )
758 {
759 epin = line;
760 }
761 }
762
763 if( !epin )
764 continue;
765
766 EASYEDAPRO::PIN_INFO pinInfo;
767 pinInfo.pin = *epin;
768
769 std::unique_ptr<SCH_PIN> pin = std::make_unique<SCH_PIN>( ksymbol );
770
771 pin->SetUnit( unitId );
772
773 pin->SetLength( ScaleSize( epin->length ) );
774 pin->SetPosition( ScalePosSym( epin->position ) );
775
776 PIN_ORIENTATION orient = PIN_ORIENTATION::PIN_RIGHT;
777
778 if( epin->rotation == 0 )
779 orient = PIN_ORIENTATION::PIN_RIGHT;
780 if( epin->rotation == 90 )
781 orient = PIN_ORIENTATION::PIN_UP;
782 if( epin->rotation == 180 )
783 orient = PIN_ORIENTATION::PIN_LEFT;
784 if( epin->rotation == 270 )
785 orient = PIN_ORIENTATION::PIN_DOWN;
786
787 pin->SetOrientation( orient );
788
790 {
791 pin->SetName( ksymbol->GetName() );
792 //pin->SetVisible( false );
793 }
794 else if( auto pinNameAttr = get_opt( pinAttributes, "NAME" ) )
795 {
796 pin->SetName( pinNameAttr->value );
797 pinInfo.name = pinNameAttr->value;
798
799 if( !pinNameAttr->valVisible )
800 pin->SetNameTextSize( schIUScale.MilsToIU( 1 ) );
801 }
802
803 if( auto pinNumAttr = get_opt( pinAttributes, "NUMBER" ) )
804 {
805 pin->SetNumber( pinNumAttr->value );
806 pinInfo.number = pinNumAttr->value;
807
808 if( !pinNumAttr->valVisible )
809 pin->SetNumberTextSize( schIUScale.MilsToIU( 1 ) );
810 }
811
813 {
814 pin->SetType( ELECTRICAL_PINTYPE::PT_POWER_IN );
815 }
816 else if( auto pinTypeAttr = get_opt( pinAttributes, "Pin Type" ) )
817 {
818 if( pinTypeAttr->value == wxS( "IN" ) )
819 pin->SetType( ELECTRICAL_PINTYPE::PT_INPUT );
820 if( pinTypeAttr->value == wxS( "OUT" ) )
821 pin->SetType( ELECTRICAL_PINTYPE::PT_OUTPUT );
822 if( pinTypeAttr->value == wxS( "BI" ) )
823 pin->SetType( ELECTRICAL_PINTYPE::PT_BIDI );
824 }
825
826 if( get_opt( pinAttributes, "NO_CONNECT" ) )
827 pin->SetType( ELECTRICAL_PINTYPE::PT_NC );
828
829 if( pin->GetNumberTextSize() * int( pin->GetNumber().size() ) > pin->GetLength() )
830 pin->SetNumberTextSize( pin->GetLength() / pin->GetNumber().size() );
831
832 symInfo.pins.push_back( pinInfo );
833 ksymbol->AddDrawItem( pin.release() );
834 }
835 }
836
837 symInfo.symbolAttr = get_opt( unitAttributes[1], "Symbol" ); // TODO: per-unit
838
839 /*BOX2I bbox = ksymbol->GetBodyBoundingBox( 0, 0, true, true );
840 bbox.Inflate( schIUScale.MilsToIU( 10 ) );*/
841
842 /*ksymbol->GetReferenceField().SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM );
843 ksymbol->GetReferenceField().SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
844 ksymbol->GetReferenceField().SetPosition( VECTOR2I( bbox.GetCenter().x, -bbox.GetTop() ) );
845
846 ksymbol->GetValueField().SetVertJustify( GR_TEXT_V_ALIGN_TOP );
847 ksymbol->GetValueField().SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
848 ksymbol->GetValueField().SetPosition( VECTOR2I( bbox.GetCenter().x, -bbox.GetBottom() ) );*/
849
850 symInfo.libSymbol = std::move( ksymbolPtr );
851
852 return symInfo;
853}
854
855
857 const nlohmann::json& aProject,
858 std::map<wxString, EASYEDAPRO::SYM_INFO>& aSymbolMap,
859 const std::map<wxString, EASYEDAPRO::BLOB>& aBlobMap,
860 const std::vector<nlohmann::json>& aLines,
861 const wxString& aLibName )
862{
863 std::vector<std::unique_ptr<SCH_ITEM>> createdItems;
864
865 std::map<wxString, std::vector<nlohmann::json>> parentedLines;
866 std::map<wxString, std::vector<nlohmann::json>> ruleLines;
867
868 std::map<wxString, nlohmann::json> lineStyles;
869 std::map<wxString, nlohmann::json> fontStyles;
870
871 for( const nlohmann::json& line : aLines )
872 {
873 wxString type = line.at( 0 );
874
875 if( type == wxS( "LINESTYLE" ) )
876 lineStyles[line.at( 1 )] = line;
877 else if( type == wxS( "FONTSTYLE" ) )
878 fontStyles[line.at( 1 )] = line;
879 }
880
881 for( const nlohmann::json& line : aLines )
882 {
883 wxString type = line.at( 0 );
884
885 if( type == wxS( "RECT" ) )
886 {
887 VECTOR2D start( line.at( 2 ), line.at( 3 ) );
888 VECTOR2D end( line.at( 4 ), line.at( 5 ) );
889 wxString styleStr = line.at( 9 );
890
891 std::unique_ptr<SCH_SHAPE> rect = std::make_unique<SCH_SHAPE>( SHAPE_T::RECTANGLE );
892
893 rect->SetStart( ScalePos( start ) );
894 rect->SetEnd( ScalePos( end ) );
895
896 ApplyLineStyle( lineStyles, rect, styleStr );
897
898 createdItems.push_back( std::move( rect ) );
899 }
900 else if( type == wxS( "CIRCLE" ) )
901 {
902 VECTOR2D center( line.at( 2 ), line.at( 3 ) );
903 double radius = line.at( 4 );
904 wxString styleStr = line.at( 5 );
905
906 std::unique_ptr<SCH_SHAPE> circle = std::make_unique<SCH_SHAPE>( SHAPE_T::CIRCLE );
907
908 circle->SetCenter( ScalePos( center ) );
909 circle->SetEnd( circle->GetCenter() + VECTOR2I( ScaleSize( radius ), 0 ) );
910
911 ApplyLineStyle( lineStyles, circle, styleStr );
912
913 createdItems.push_back( std::move( circle ) );
914 }
915 else if( type == wxS( "POLY" ) )
916 {
917 std::vector<double> points = line.at( 2 );
918 wxString styleStr = line.at( 4 );
919
920 SHAPE_LINE_CHAIN chain;
921
922 for( size_t i = 1; i < points.size(); i += 2 )
923 chain.Append( ScalePos( VECTOR2D( points[i - 1], points[i] ) ) );
924
925 for( int segId = 0; segId < chain.SegmentCount(); segId++ )
926 {
927 const SEG& seg = chain.CSegment( segId );
928
929 std::unique_ptr<SCH_LINE> schLine =
930 std::make_unique<SCH_LINE>( seg.A, LAYER_NOTES );
931 schLine->SetEndPoint( seg.B );
932
933 ApplyLineStyle( lineStyles, schLine, styleStr );
934
935 createdItems.push_back( std::move( schLine ) );
936 }
937 }
938 else if( type == wxS( "TEXT" ) )
939 {
940 VECTOR2D pos( line.at( 2 ), line.at( 3 ) );
941 double angle = line.at( 4 );
942 wxString textStr = line.at( 5 );
943 wxString fontStyleStr = line.at( 6 );
944
945 std::unique_ptr<SCH_TEXT> text =
946 std::make_unique<SCH_TEXT>( ScalePos( pos ), UnescapeHTML( textStr ) );
947
948 text->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
949 text->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
950
951 text->SetTextAngleDegrees( angle );
952
953 ApplyFontStyle( fontStyles, text, fontStyleStr );
954
955 createdItems.push_back( std::move( text ) );
956 }
957 else if( type == wxS( "OBJ" ) )
958 {
959 VECTOR2D start, size;
960 wxString mimeType, base64Data;
961 double angle = 0;
962 int flipped = 0;
963
964 if( line.at( 3 ).is_number() )
965 {
966 start = VECTOR2D( line.at( 3 ), line.at( 4 ) );
967 size = VECTOR2D( line.at( 5 ), line.at( 6 ) );
968 angle = line.at( 7 );
969 flipped = line.at( 8 );
970
971 wxString imageUrl = line.at( 9 );
972
973 if( imageUrl.BeforeFirst( ':' ) == wxS( "data" ) )
974 {
975 wxArrayString paramsArr =
976 wxSplit( imageUrl.AfterFirst( ':' ).BeforeFirst( ',' ), ';', '\0' );
977
978 base64Data = imageUrl.AfterFirst( ',' );
979
980 if( paramsArr.size() > 0 )
981 mimeType = paramsArr[0];
982 }
983 else if( imageUrl.BeforeFirst( ':' ) == wxS( "blob" ) )
984 {
985 wxString objectId = imageUrl.AfterLast( ':' );
986
987 if( auto blob = get_opt( aBlobMap, objectId ) )
988 {
989 wxString blobUrl = blob->url;
990
991 if( blobUrl.BeforeFirst( ':' ) == wxS( "data" ) )
992 {
993 wxArrayString paramsArr = wxSplit(
994 blobUrl.AfterFirst( ':' ).BeforeFirst( ',' ), ';', '\0' );
995
996 base64Data = blobUrl.AfterFirst( ',' );
997
998 if( paramsArr.size() > 0 )
999 mimeType = paramsArr[0];
1000 }
1001 }
1002 }
1003 }
1004 else if( line.at( 3 ).is_string() )
1005 {
1006 mimeType = line.at( 3 ).get<wxString>().BeforeFirst( ';' );
1007
1008 start = VECTOR2D( line.at( 4 ), line.at( 5 ) );
1009 size = VECTOR2D( line.at( 6 ), line.at( 7 ) );
1010 angle = line.at( 8 );
1011 base64Data = line.at( 9 ).get<wxString>();
1012 }
1013
1014 VECTOR2D kstart = ScalePos( start );
1015 VECTOR2D ksize = ScaleSize( size );
1016
1017 if( mimeType.empty() || base64Data.empty() )
1018 continue;
1019
1020 wxMemoryBuffer buf = wxBase64Decode( base64Data );
1021
1022 if( mimeType == wxS( "image/svg+xml" ) )
1023 {
1024 SVG_IMPORT_PLUGIN svgImportPlugin;
1025 GRAPHICS_IMPORTER_SCH schImporter;
1026
1027 svgImportPlugin.SetImporter( &schImporter );
1028 svgImportPlugin.LoadFromMemory( buf );
1029
1030 VECTOR2D imSize( svgImportPlugin.GetImageWidth(),
1031 svgImportPlugin.GetImageHeight() );
1032
1033 VECTOR2D pixelScale( schIUScale.IUTomm( ScaleSize( size.x ) ) / imSize.x,
1034 schIUScale.IUTomm( ScaleSize( size.y ) ) / imSize.y );
1035
1036 schImporter.SetScale( pixelScale );
1037
1038 VECTOR2D offsetMM( schIUScale.IUTomm( kstart.x ), schIUScale.IUTomm( kstart.y ) );
1039
1040 schImporter.SetImportOffsetMM( offsetMM );
1041
1042 svgImportPlugin.Import();
1043
1044 for( std::unique_ptr<EDA_ITEM>& item : schImporter.GetItems() )
1045 {
1046 SCH_ITEM* schItem = static_cast<SCH_ITEM*>( item.release() );
1047
1048 for( double i = angle; i > 0; i -= 90 )
1049 {
1050 if( schItem->Type() == SCH_LINE_T )
1051 {
1052 // Lines need special handling for some reason
1053 schItem->SetFlags( STARTPOINT );
1054 schItem->Rotate( kstart, false );
1055 schItem->ClearFlags( STARTPOINT );
1056
1057 schItem->SetFlags( ENDPOINT );
1058 schItem->Rotate( kstart, false );
1059 schItem->ClearFlags( ENDPOINT );
1060 }
1061 else
1062 {
1063 schItem->Rotate( kstart, false );
1064 }
1065 }
1066
1067 if( flipped )
1068 {
1069 // Lines need special handling for some reason
1070 if( schItem->Type() == SCH_LINE_T )
1071 schItem->SetFlags( STARTPOINT | ENDPOINT );
1072
1073 schItem->MirrorHorizontally( kstart.x );
1074
1075 if( schItem->Type() == SCH_LINE_T )
1076 schItem->ClearFlags( STARTPOINT | ENDPOINT );
1077 }
1078
1079 createdItems.emplace_back( schItem );
1080 }
1081 }
1082 else
1083 {
1084 std::unique_ptr<SCH_BITMAP> bitmap = std::make_unique<SCH_BITMAP>();
1085 REFERENCE_IMAGE& refImage = bitmap->GetReferenceImage();
1086
1087 wxImage::SetDefaultLoadFlags( wxImage::GetDefaultLoadFlags()
1088 & ~wxImage::Load_Verbose );
1089
1090 if( refImage.ReadImageFile( buf ) )
1091 {
1092 VECTOR2D kcenter = kstart + ksize / 2;
1093
1094 double scaleFactor = ScaleSize( size.x ) / refImage.GetSize().x;
1095 refImage.SetImageScale( scaleFactor );
1096 bitmap->SetPosition( kcenter );
1097
1098 for( double i = angle; i > 0; i -= 90 )
1099 bitmap->Rotate( kstart, false );
1100
1101 if( flipped )
1102 bitmap->MirrorHorizontally( kstart.x );
1103
1104 createdItems.push_back( std::move( bitmap ) );
1105 }
1106 }
1107 }
1108 if( type == wxS( "WIRE" ) )
1109 {
1110 wxString wireId = line.at( 1 );
1111 parentedLines[wireId].push_back( line );
1112 }
1113 else if( type == wxS( "COMPONENT" ) )
1114 {
1115 wxString compId = line.at( 1 );
1116 parentedLines[compId].push_back( line );
1117 }
1118 else if( type == wxS( "ATTR" ) )
1119 {
1120 wxString compId = line.at( 2 );
1121 parentedLines[compId].push_back( line );
1122 }
1123 }
1124
1125 for( auto& [parentId, lines] : parentedLines )
1126 {
1127 std::optional<EASYEDAPRO::SCH_COMPONENT> component;
1128 std::optional<EASYEDAPRO::SCH_WIRE> wire;
1129 std::map<wxString, EASYEDAPRO::SCH_ATTR> attributes;
1130
1131 for( const nlohmann::json& line : lines )
1132 {
1133 if( line.at( 0 ) == "COMPONENT" )
1134 {
1135 component = line;
1136 }
1137 else if( line.at( 0 ) == "WIRE" )
1138 {
1139 wire = line;
1140 }
1141 else if( line.at( 0 ) == "ATTR" )
1142 {
1143 EASYEDAPRO::SCH_ATTR attr = line;
1144 attributes.emplace( attr.key, attr );
1145 }
1146 }
1147
1148 if( component )
1149 {
1150 auto deviceAttr = get_opt( attributes, "Device" );
1151 auto symbolAttr = get_opt( attributes, "Symbol" );
1152
1153 if( !deviceAttr )
1154 continue;
1155
1156 std::map<wxString, wxString> compAttrs = EASYEDAPRO::AnyMapToStringMap(
1157 aProject.at( "devices" ).at( deviceAttr->value ).at( "attributes" ) );
1158
1159 wxString symbolId;
1160
1161 if( symbolAttr && !symbolAttr->value.IsEmpty() )
1162 symbolId = symbolAttr->value;
1163 else
1164 symbolId = compAttrs.at( "Symbol" );
1165
1166 auto it = aSymbolMap.find( symbolId );
1167 if( it == aSymbolMap.end() )
1168 {
1169 wxLogError( "Symbol of '%s' with uuid '%s' not found.", component->name, symbolId );
1170 continue;
1171 }
1172
1173 EASYEDAPRO::SYM_INFO& esymInfo = it->second;
1174 LIB_SYMBOL newLibSymbol = *esymInfo.libSymbol.get();
1175
1176 wxString unitName = component->name;
1177
1178 LIB_ID libId = EASYEDAPRO::ToKiCadLibID( aLibName,
1179 newLibSymbol.GetLibId().GetLibItemName() );
1180
1181 auto schSym = std::make_unique<SCH_SYMBOL>( newLibSymbol, libId,
1182 &aSchematic->CurrentSheet(),
1183 esymInfo.partUnits[unitName] );
1184
1185 schSym->SetFootprintFieldText( newLibSymbol.GetFootprintField().GetText() );
1186
1187 for( double i = component->rotation; i > 0; i -= 90 )
1188 schSym->Rotate( VECTOR2I(), true );
1189
1190 if( component->mirror )
1191 schSym->MirrorHorizontally( 0 );
1192
1193 schSym->SetPosition( ScalePos( component->position ) );
1194
1196 {
1197 if( auto globalNetAttr = get_opt( attributes, "Global Net Name" ) )
1198 {
1199 ApplyAttrToField( fontStyles, schSym->GetField( VALUE_FIELD ), *globalNetAttr,
1200 false, true, compAttrs, schSym.get() );
1201
1202 for( SCH_PIN* pin : schSym->GetAllLibPins() )
1203 pin->SetName( globalNetAttr->value );
1204 }
1205 else
1206 {
1207 schSym->GetField( VALUE_FIELD )
1208 ->SetText( newLibSymbol.GetValueField().GetText() );
1209 }
1210
1211 schSym->SetRef( &aSchematic->CurrentSheet(), wxS( "#PWR?" ) );
1212 schSym->GetField( REFERENCE_FIELD )->SetVisible( false );
1213 }
1214 else if( esymInfo.head.symbolType == EASYEDAPRO::SYMBOL_TYPE::NETPORT )
1215 {
1216 auto nameAttr = get_opt( attributes, "Name" );
1217
1218 wxString netName;
1219
1220 if( nameAttr && !nameAttr->value.IsEmpty() )
1221 netName = nameAttr->value;
1222 else
1223 netName = compAttrs.at( "Name" );
1224
1225 std::unique_ptr<SCH_GLOBALLABEL> label = std::make_unique<SCH_GLOBALLABEL>(
1226 ScalePos( component->position ), netName );
1227
1228 std::vector<SCH_PIN*> pins = schSym->GetPins( &aSchematic->CurrentSheet() );
1229
1230 if( pins.size() > 0 )
1231 {
1232 switch( pins[0]->GetType() )
1233 {
1234 case ELECTRICAL_PINTYPE::PT_INPUT:
1235 label->SetShape( LABEL_FLAG_SHAPE::L_INPUT );
1236 break;
1237 case ELECTRICAL_PINTYPE::PT_OUTPUT:
1238 label->SetShape( LABEL_FLAG_SHAPE::L_OUTPUT );
1239 break;
1240 case ELECTRICAL_PINTYPE::PT_BIDI:
1241 label->SetShape( LABEL_FLAG_SHAPE::L_BIDI );
1242 break;
1243 default: break;
1244 }
1245 }
1246
1247 BOX2I bbox = schSym->GetBodyAndPinsBoundingBox();
1248 bbox.Offset( -schSym->GetPosition() );
1249 VECTOR2I bboxCenter = bbox.GetCenter();
1250
1252
1253 if( std::abs( bboxCenter.x ) >= std::abs( bboxCenter.y ) )
1254 {
1255 if( bboxCenter.x >= 0 )
1256 spin = SPIN_STYLE::RIGHT;
1257 else
1258 spin = SPIN_STYLE::LEFT;
1259 }
1260 else
1261 {
1262 if( bboxCenter.y >= 0 )
1263 spin = SPIN_STYLE::BOTTOM;
1264 else
1265 spin = SPIN_STYLE::UP;
1266 }
1267
1268 label->SetSpinStyle( spin );
1269
1270 if( nameAttr )
1271 {
1272 nlohmann::json style = fontStyles[nameAttr->fontStyle];
1273
1274 if( !style.is_null() && style.at( 5 ).is_number() )
1275 {
1276 double size = style.at( 5 ).get<double>() * 0.5;
1277 label->SetTextSize( VECTOR2I( ScaleSize( size ), ScaleSize( size ) ) );
1278 }
1279 }
1280
1281 createdItems.push_back( std::move( label ) );
1282
1283 continue;
1284 }
1285 else
1286 {
1287 for( const wxString& attrKey : c_attributesWhitelist )
1288 {
1289 if( auto valOpt = get_opt( compAttrs, attrKey ) )
1290 {
1291 if( valOpt->empty() )
1292 continue;
1293
1294 SCH_FIELD* text = schSym->FindField( attrKey, true );
1295
1296 if( !text )
1297 {
1298 text = schSym->AddField(
1299 SCH_FIELD( schSym.get(), schSym->GetFieldCount(), attrKey ) );
1300 }
1301
1302 wxString value = *valOpt;
1303
1304 value.Replace( wxS( "\u2103" ), wxS( "\u00B0C" ), true ); // ℃ -> °C
1305
1306 text->SetText( value );
1307 text->SetVisible( false );
1308 }
1309 }
1310
1311 auto nameAttr = get_opt( attributes, "Name" );
1312 auto valueAttr = get_opt( attributes, "Value" );
1313
1314 if( valueAttr && valueAttr->value.empty() )
1315 valueAttr->value = get_def( compAttrs, "Value", wxString() );
1316
1317 if( nameAttr && nameAttr->value.empty() )
1318 nameAttr->value = get_def( compAttrs, "Name", wxString() );
1319
1320 std::optional<EASYEDAPRO::SCH_ATTR> targetValueAttr;
1321
1322 if( valueAttr && !valueAttr->value.empty() && valueAttr->valVisible )
1323 targetValueAttr = valueAttr;
1324 else if( nameAttr && !nameAttr->value.empty() && nameAttr->valVisible )
1325 targetValueAttr = nameAttr;
1326 else if( valueAttr && !valueAttr->value.empty() )
1327 targetValueAttr = valueAttr;
1328 else if( nameAttr && !nameAttr->value.empty() )
1329 targetValueAttr = nameAttr;
1330
1331 if( targetValueAttr )
1332 {
1333 ApplyAttrToField( fontStyles, schSym->GetField( VALUE_FIELD ), *targetValueAttr,
1334 false, true, compAttrs, schSym.get() );
1335 }
1336
1337 if( auto descrAttr = get_opt( attributes, "Description" ) )
1338 {
1339 ApplyAttrToField( fontStyles, schSym->GetField( DESCRIPTION_FIELD ), *descrAttr,
1340 false, true, compAttrs, schSym.get() );
1341 }
1342
1343 if( auto designatorAttr = get_opt( attributes, "Designator" ) )
1344 {
1345 ApplyAttrToField( fontStyles, schSym->GetField( REFERENCE_FIELD ),
1346 *designatorAttr, false, true, compAttrs, schSym.get() );
1347
1348 schSym->SetRef( &aSchematic->CurrentSheet(), designatorAttr->value );
1349 }
1350
1351 for( auto& [attrKey, attr] : attributes )
1352 {
1353 if( attrKey == wxS( "Name" ) || attrKey == wxS( "Value" )
1354 || attrKey == wxS( "Global Net Name" ) || attrKey == wxS( "Designator" )
1355 || attrKey == wxS( "Description" ) || attrKey == wxS( "Device" )
1356 || attrKey == wxS( "Footprint" ) || attrKey == wxS( "Symbol" )
1357 || attrKey == wxS( "Unique ID" ) )
1358 {
1359 continue;
1360 }
1361
1362 if( attr.value.IsEmpty() )
1363 continue;
1364
1365 SCH_FIELD* text = schSym->FindField( attrKey, true );
1366
1367 if( !text )
1368 {
1369 text = schSym->AddField(
1370 SCH_FIELD( schSym.get(), schSym->GetFieldCount(), attrKey ) );
1371 }
1372
1373 text->SetPosition( schSym->GetPosition() );
1374
1375 ApplyAttrToField( fontStyles, text, attr, false, true, compAttrs,
1376 schSym.get() );
1377 }
1378 }
1379
1380 for( const EASYEDAPRO::PIN_INFO& pinInfo : esymInfo.pins )
1381 {
1382 wxString pinKey = parentId + pinInfo.pin.id;
1383 auto pinLines = get_opt( parentedLines, pinKey );
1384
1385 if( !pinLines )
1386 continue;
1387
1388 for( const nlohmann::json& pinLine : *pinLines )
1389 {
1390 if( pinLine.at( 0 ) != "ATTR" )
1391 continue;
1392
1393 EASYEDAPRO::SCH_ATTR attr = pinLine;
1394
1395 if( attr.key != wxS( "NO_CONNECT" ) )
1396 continue;
1397
1398 if( SCH_PIN* schPin = schSym->GetPin( pinInfo.number ) )
1399 {
1400 VECTOR2I pos = schSym->GetPinPhysicalPosition( schPin->GetLibPin() );
1401
1402 std::unique_ptr<SCH_NO_CONNECT> noConn =
1403 std::make_unique<SCH_NO_CONNECT>( pos );
1404
1405 createdItems.push_back( std::move( noConn ) );
1406 }
1407 }
1408 }
1409
1410 createdItems.push_back( std::move( schSym ) );
1411 }
1412 else // Not component
1413 {
1414 std::vector<SHAPE_LINE_CHAIN> wireLines;
1415
1416 if( wire )
1417 {
1418 for( const std::vector<double>& ptArr : wire->geometry )
1419 {
1420 SHAPE_LINE_CHAIN chain;
1421
1422 for( size_t i = 1; i < ptArr.size(); i += 2 )
1423 chain.Append( ScalePos( VECTOR2D( ptArr[i - 1], ptArr[i] ) ) );
1424
1425 if( chain.PointCount() < 2 )
1426 continue;
1427
1428 wireLines.push_back( chain );
1429
1430 for( int segId = 0; segId < chain.SegmentCount(); segId++ )
1431 {
1432 const SEG& seg = chain.CSegment( segId );
1433
1434 std::unique_ptr<SCH_LINE> schLine =
1435 std::make_unique<SCH_LINE>( seg.A, LAYER_WIRE );
1436 schLine->SetEndPoint( seg.B );
1437
1438 createdItems.push_back( std::move( schLine ) );
1439 }
1440 }
1441 }
1442
1443 auto netAttr = get_opt( attributes, "NET" );
1444
1445 if( netAttr )
1446 {
1447 if( !netAttr->valVisible || netAttr->value.IsEmpty() )
1448 continue;
1449
1450 VECTOR2I kpos = ScalePos( *netAttr->position );
1451 VECTOR2I nearestPos = kpos;
1452 SEG::ecoord min_dist_sq = VECTOR2I::ECOORD_MAX;
1453
1454 for( const SHAPE_LINE_CHAIN& chain : wireLines )
1455 {
1456 VECTOR2I nearestPt = chain.NearestPoint( kpos, false );
1457 SEG::ecoord dist_sq = ( nearestPt - kpos ).SquaredEuclideanNorm();
1458
1459 if( dist_sq < min_dist_sq )
1460 {
1461 min_dist_sq = dist_sq;
1462 nearestPos = nearestPt;
1463 }
1464 }
1465
1466 std::unique_ptr<SCH_LABEL> label = std::make_unique<SCH_LABEL>();
1467
1468 label->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
1469 label->SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM );
1470
1471 for( double i = netAttr->rotation; i > 0; i -= 90 )
1472 label->Rotate90( true );
1473
1474 label->SetPosition( nearestPos );
1475 label->SetText( netAttr->value );
1476
1477 ApplyFontStyle( fontStyles, label, netAttr->fontStyle );
1478
1479 createdItems.push_back( std::move( label ) );
1480 }
1481 }
1482 }
1483
1484 // Adjust page to content
1485 BOX2I sheetBBox;
1486
1487 for( std::unique_ptr<SCH_ITEM>& ptr : createdItems )
1488 {
1489 if( ptr->Type() == SCH_SYMBOL_T )
1490 sheetBBox.Merge( static_cast<SCH_SYMBOL*>( ptr.get() )->GetBodyAndPinsBoundingBox() );
1491 else
1492 sheetBBox.Merge( ptr->GetBoundingBox() );
1493 }
1494
1495 SCH_SCREEN* screen = aRootSheet->GetScreen();
1496 PAGE_INFO pageInfo = screen->GetPageSettings();
1497
1498 int alignGrid = schIUScale.MilsToIU( 50 );
1499
1500 VECTOR2D offset( -sheetBBox.GetLeft(), -sheetBBox.GetTop() );
1501 offset.x = KiROUND( offset.x / alignGrid ) * alignGrid;
1502 offset.y = KiROUND( offset.y / alignGrid ) * alignGrid;
1503
1504 pageInfo.SetWidthMils( schIUScale.IUToMils( sheetBBox.GetWidth() ) );
1505 pageInfo.SetHeightMils( schIUScale.IUToMils( sheetBBox.GetHeight() ) );
1506
1507 screen->SetPageSettings( pageInfo );
1508
1509 for( std::unique_ptr<SCH_ITEM>& ptr : createdItems )
1510 {
1511 ptr->Move( offset );
1512 screen->Append( ptr.release() );
1513 }
1514}
int color
Definition: DXF_plotter.cpp:58
constexpr EDA_IU_SCALE schIUScale
Definition: base_units.h:110
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition: box2.h:990
constexpr size_type GetWidth() const
Definition: box2.h:214
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 size_type GetHeight() const
Definition: box2.h:215
constexpr coord_type GetLeft() const
Definition: box2.h:228
constexpr coord_type GetTop() const
Definition: box2.h:229
constexpr void Offset(coord_type dx, coord_type dy)
Definition: box2.h:259
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:127
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:101
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: eda_item.h:129
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:79
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:94
virtual void SetVisible(bool aVisible)
Definition: eda_text.cpp:290
void SetImportOffsetMM(const VECTOR2D &aOffset)
Set the offset in millimeters to add to coordinates when importing graphic items.
void SetScale(const VECTOR2D &aScale)
Set the scale factor affecting the imported shapes.
std::list< std::unique_ptr< EDA_ITEM > > & GetItems()
Return the list of objects representing the imported shapes.
virtual void SetImporter(GRAPHICS_IMPORTER *aImporter)
Set the receiver of the imported shapes.
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 color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:104
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:49
const UTF8 & GetLibItemName() const
Definition: lib_id.h:102
Define a library symbol object.
Definition: lib_symbol.h:78
const LIB_ID & GetLibId() const override
Definition: lib_symbol.h:143
void SetUnitCount(int aCount, bool aDuplicateDrawItems=true)
Set the units per symbol count.
int GetNextAvailableFieldId() const
SCH_FIELD & GetValueField() const
Return reference to the value field.
void SetPower()
Definition: lib_symbol.cpp:405
SCH_FIELD & GetFootprintField() const
Return reference to the footprint field.
wxString GetName() const override
Definition: lib_symbol.h:137
void SetDescription(const wxString &aDescription)
Gets the Description field text value *‍/.
Definition: lib_symbol.h:152
void SetKeyWords(const wxString &aKeyWords)
Definition: lib_symbol.h:169
SCH_FIELD & GetReferenceField() const
Return reference to the reference designator field.
SCH_FIELD * FindField(const wxString &aFieldName, bool aCaseInsensitive=false)
Find a field within this symbol matching aFieldName and returns it or NULL if not found.
void AddField(SCH_FIELD *aField)
Add a field.
void AddDrawItem(SCH_ITEM *aItem, bool aSort=true)
Add a new draw aItem to the draw object list and sort according to aSort.
Definition: lib_symbol.cpp:796
Describe the page size and margins of a paper page on which to eventually print or plot.
Definition: page_info.h:59
void SetHeightMils(double aHeightInMils)
Definition: page_info.cpp:261
void SetWidthMils(double aWidthInMils)
Definition: page_info.cpp:247
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...
bool ReadImageFile(const wxString &aFullFilename)
Read and store an image file.
VECTOR2I GetSize() const
void SetImageScale(double aScale)
Set the image "zoom" value.
Holds all the data relating to one schematic.
Definition: schematic.h:77
SCH_SHEET_PATH & CurrentSheet() const override
Definition: schematic.h:152
static double Convert(wxString aValue)
static VECTOR2< T > ScalePos(VECTOR2< T > aValue)
double SizeToKi(wxString units)
static T ScaleSize(T aValue)
void ApplyFontStyle(const std::map< wxString, nlohmann::json > &fontStyles, T &text, const wxString &styleStr)
static VECTOR2< T > ScalePosSym(VECTOR2< T > aValue)
SCH_EASYEDAPRO_PARSER(SCHEMATIC *aSchematic, PROGRESS_REPORTER *aProgressReporter)
EASYEDAPRO::SYM_INFO ParseSymbol(const std::vector< nlohmann::json > &aLines, const std::map< wxString, wxString > &aDeviceAttributes)
void ApplyAttrToField(const std::map< wxString, nlohmann::json > &fontStyles, T *text, const EASYEDAPRO::SCH_ATTR &aAttr, bool aIsSym, bool aToSym, const std::map< wxString, wxString > &aDeviceAttributes={}, SCH_SYMBOL *aParent=nullptr)
void ParseSchematic(SCHEMATIC *aSchematic, SCH_SHEET *aRootSheet, const nlohmann::json &aProject, std::map< wxString, EASYEDAPRO::SYM_INFO > &aSymbolMap, const std::map< wxString, EASYEDAPRO::BLOB > &aBlobMap, const std::vector< nlohmann::json > &aLines, const wxString &aLibName)
wxString ResolveFieldVariables(const wxString aInput, const std::map< wxString, wxString > &aDeviceAttributes)
void ApplyLineStyle(const std::map< wxString, nlohmann::json > &lineStyles, T &shape, const wxString &styleStr)
Instances are attached to a symbol or sheet and provide a place for the symbol's value,...
Definition: sch_field.h:51
void SetText(const wxString &aText) override
Definition: sch_field.cpp:1212
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:166
virtual void MirrorHorizontally(int aCenter)
Mirror item horizontally about aCenter.
Definition: sch_item.h:343
virtual void Rotate(const VECTOR2I &aCenter, bool aRotateCCW)
Rotate the item around aCenter 90 degrees in the clockwise direction.
Definition: sch_item.h:359
const PAGE_INFO & GetPageSettings() const
Definition: sch_screen.h:130
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Definition: sch_screen.cpp:153
void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition: sch_screen.h:131
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:57
SCH_SCREEN * GetScreen() const
Definition: sch_sheet.h:110
Schematic symbol object.
Definition: sch_symbol.h:104
BOX2I GetBodyAndPinsBoundingBox() const
Return a bounding box for the symbol body and pins but not the fields.
Definition: seg.h:42
VECTOR2I A
Definition: seg.h:49
VECTOR2I::extended_type ecoord
Definition: seg.h:44
VECTOR2I B
Definition: seg.h:50
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
int PointCount() const
Return the number of points (vertices) in this line chain.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
int SegmentCount() const
Return the number of segments in this line chain.
const SEG CSegment(int aIndex) const
Return a constant copy of the aIndex segment in the line chain.
Simple container to manage line stroke parameters.
Definition: stroke_params.h:79
void SetLineStyle(LINE_STYLE aLineStyle)
Definition: stroke_params.h:93
void SetWidth(int aWidth)
Definition: stroke_params.h:90
void SetColor(const KIGFX::COLOR4D &aColor)
Definition: stroke_params.h:96
bool Import() override
Actually imports the file.
virtual double GetImageWidth() const override
Return image width from original imported file.
bool LoadFromMemory(const wxMemoryBuffer &aMemBuffer) override
Set memory buffer with content for import.
virtual double GetImageHeight() const override
Return image height from original imported file.
virtual void SetShowPinNumbers(bool aShow)
Set or clear the pin number visibility flag.
Definition: symbol.h:129
virtual void SetShowPinNames(bool aShow)
Set or clear the pin name visibility flag.
Definition: symbol.h:123
static constexpr extended_type ECOORD_MAX
Definition: vector2d.h:76
#define _(s)
static constexpr EDA_ANGLE ANGLE_VERTICAL
Definition: eda_angle.h:398
static constexpr EDA_ANGLE ANGLE_HORIZONTAL
Definition: eda_angle.h:397
#define ENDPOINT
ends. (Used to support dragging.)
#define STARTPOINT
When a line is selected, these flags indicate which.
void ConvertImageToLibShapes(LIB_SYMBOL *aSymbol, int unit, wxImage img, VECTOR2D pixelScale, VECTOR2D offset)
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:39
@ LAYER_DEVICE
Definition: layer_ids.h:370
@ LAYER_WIRE
Definition: layer_ids.h:356
@ LAYER_NOTES
Definition: layer_ids.h:371
wxString get_def(const std::map< wxString, wxString > &aMap, const char *aKey, const char *aDefval="")
Definition: map_helpers.h:64
std::optional< V > get_opt(const std::map< wxString, V > &aMap, const wxString &aKey)
Definition: map_helpers.h:34
LIB_ID ToKiCadLibID(const wxString &aLibName, const wxString &aLibReference)
std::map< wxString, wxString > AnyMapToStringMap(const std::map< wxString, nlohmann::json > &aInput)
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:390
PIN_ORIENTATION
The symbol library pin object orientations.
Definition: pin_type.h:78
static const std::vector< wxString > c_attributesWhitelist
static LINE_STYLE ConvertStrokeStyle(const wxString &aStyle)
static const std::vector< wxString > c_attributesWhitelist
static LINE_STYLE ConvertStrokeStyle(int aStyle)
@ SYM_ORIENT_270
Definition: sch_symbol.h:83
@ SYM_MIRROR_Y
Definition: sch_symbol.h:85
@ SYM_ORIENT_180
Definition: sch_symbol.h:82
@ SYM_MIRROR_X
Definition: sch_symbol.h:84
@ SYM_ORIENT_90
Definition: sch_symbol.h:81
@ SYM_ORIENT_0
Definition: sch_symbol.h:80
const int scale
wxString UnescapeHTML(const wxString &aString)
Return a new wxString unescaped from HTML format.
LINE_STYLE
Dashed line types.
Definition: stroke_params.h:46
EASYEDAPRO::SYM_PIN pin
std::optional< VECTOR2D > position
std::unique_ptr< LIB_SYMBOL > libSymbol
std::vector< PIN_INFO > pins
std::optional< EASYEDAPRO::SCH_ATTR > symbolAttr
std::map< wxString, int > partUnits
EASYEDAPRO::SYM_HEAD head
constexpr double IUTomm(int iu) const
Definition: base_units.h:86
constexpr int IUToMils(int iu) const
Definition: base_units.h:99
constexpr int MilsToIU(int mils) const
Definition: base_units.h:93
@ VALUE_FIELD
Field Value of part, i.e. "3.3K".
@ REFERENCE_FIELD
Field Reference of part, i.e. "IC21".
@ DESCRIPTION_FIELD
Field Description of part, i.e. "1/4W 1% Metal Film Resistor".
GR_TEXT_H_ALIGN_T
@ GR_TEXT_H_ALIGN_CENTER
@ GR_TEXT_H_ALIGN_RIGHT
@ GR_TEXT_H_ALIGN_LEFT
GR_TEXT_V_ALIGN_T
@ GR_TEXT_V_ALIGN_BOTTOM
@ GR_TEXT_V_ALIGN_CENTER
@ GR_TEXT_V_ALIGN_TOP
@ SCH_LINE_T
Definition: typeinfo.h:163
@ SCH_SYMBOL_T
Definition: typeinfo.h:172
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:691
VECTOR2< double > VECTOR2D
Definition: vector2d.h:690