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 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 <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
308 if( aIsSym )
309 {
310 text->SetVisible( aAttr.keyVisible || aAttr.valVisible );
311 field->SetNameShown( aAttr.keyVisible );
312 }
313
314 if( aAttr.position )
315 {
316 field->SetPosition( !aIsSym ? ScalePos( *aAttr.position )
317 : ScalePosSym( *aAttr.position ) );
318 }
319
320 if( aIsSym )
321 ApplyFontStyle( fontStyles, text, aAttr.fontStyle );
322
323 auto parent = aParent;
324 if( parent && parent->Type() == SCH_SYMBOL_T )
325 {
326 int orient = static_cast<SCH_SYMBOL*>( parent )->GetOrientation();
327
328 if( orient == SYM_ORIENT_180 )
329 {
330 text->SetVertJustify( static_cast<GR_TEXT_V_ALIGN_T>( -text->GetVertJustify() ) );
331 text->SetHorizJustify( static_cast<GR_TEXT_H_ALIGN_T>( -text->GetHorizJustify() ) );
332 }
333 else if( orient == SYM_MIRROR_X + SYM_ORIENT_0 )
334 {
335 text->SetVertJustify( static_cast<GR_TEXT_V_ALIGN_T>( -text->GetVertJustify() ) );
336 }
337 else if( orient == SYM_MIRROR_Y + SYM_ORIENT_0 )
338 {
339 text->SetHorizJustify( static_cast<GR_TEXT_H_ALIGN_T>( -text->GetHorizJustify() ) );
340 }
341 else if( orient == SYM_MIRROR_Y + SYM_ORIENT_180 )
342 {
343 text->SetHorizJustify( static_cast<GR_TEXT_H_ALIGN_T>( text->GetHorizJustify() ) );
344 }
345 else if( orient == SYM_ORIENT_90 )
346 {
347 text->SetTextAngle( ANGLE_VERTICAL );
348 text->SetVertJustify( static_cast<GR_TEXT_V_ALIGN_T>( -text->GetVertJustify() ) );
349 text->SetHorizJustify( static_cast<GR_TEXT_H_ALIGN_T>( -text->GetHorizJustify() ) );
350 }
351 if( orient == SYM_ORIENT_270 )
352 {
353 text->SetTextAngle( ANGLE_VERTICAL );
354 }
355 else if( orient == SYM_MIRROR_X + SYM_ORIENT_90 )
356 {
357 text->SetTextAngle( ANGLE_VERTICAL );
358 text->SetVertJustify( static_cast<GR_TEXT_V_ALIGN_T>( -text->GetVertJustify() ) );
359 text->SetHorizJustify( static_cast<GR_TEXT_H_ALIGN_T>( -text->GetHorizJustify() ) );
360 }
361 else if( orient == SYM_MIRROR_X + SYM_ORIENT_270 )
362 {
363 text->SetTextAngle( ANGLE_VERTICAL );
364 text->SetVertJustify( static_cast<GR_TEXT_V_ALIGN_T>( -text->GetVertJustify() ) );
365 }
366 else if( orient == SYM_MIRROR_Y + SYM_ORIENT_90 )
367 {
368 text->SetTextAngle( ANGLE_VERTICAL );
369 text->SetHorizJustify( static_cast<GR_TEXT_H_ALIGN_T>( -text->GetHorizJustify() ) );
370 }
371 else if( orient == SYM_MIRROR_Y + SYM_ORIENT_270 )
372 {
373 text->SetHorizJustify( static_cast<GR_TEXT_H_ALIGN_T>( text->GetHorizJustify() ) );
374 }
375
376 if( aAttr.rotation == 90 )
377 {
378 if( text->GetTextAngle() == ANGLE_HORIZONTAL )
379 text->SetTextAngle( ANGLE_VERTICAL );
380 else
381 text->SetTextAngle( ANGLE_HORIZONTAL );
382
383 if( orient == SYM_ORIENT_90 )
384 {
385 text->SetVertJustify( static_cast<GR_TEXT_V_ALIGN_T>( -text->GetVertJustify() ) );
386 text->SetHorizJustify( static_cast<GR_TEXT_H_ALIGN_T>( -text->GetHorizJustify() ) );
387 }
388 if( orient == SYM_ORIENT_270 )
389 {
390 text->SetVertJustify( static_cast<GR_TEXT_V_ALIGN_T>( -text->GetVertJustify() ) );
391 text->SetHorizJustify( static_cast<GR_TEXT_H_ALIGN_T>( -text->GetHorizJustify() ) );
392 }
393 else if( orient == SYM_MIRROR_X + SYM_ORIENT_90 )
394 {
395 text->SetVertJustify( static_cast<GR_TEXT_V_ALIGN_T>( -text->GetVertJustify() ) );
396 }
397 }
398 }
399}
400
401
403SCH_EASYEDAPRO_PARSER::ParseSymbol( const std::vector<nlohmann::json>& aLines,
404 const std::map<wxString, wxString>& aDeviceAttributes )
405{
406 EASYEDAPRO::SYM_INFO symInfo;
407
408 std::unique_ptr<LIB_SYMBOL> ksymbolPtr = std::make_unique<LIB_SYMBOL>( wxEmptyString );
409 LIB_SYMBOL* ksymbol = ksymbolPtr.get();
410
411 std::map<wxString, nlohmann::json> lineStyles;
412 std::map<wxString, nlohmann::json> fontStyles;
413 std::map<wxString, int> partUnits;
414
415 std::map<int, std::map<wxString, EASYEDAPRO::SCH_ATTR>> unitAttributes;
416 std::map<int, std::map<wxString, std::vector<nlohmann::json>>> unitParentedLines;
417
418 int totalUnits = 0;
419
420 for( const nlohmann::json& line : aLines )
421 {
422 wxString type = line.at( 0 );
423
424 if( type == wxS( "LINESTYLE" ) )
425 lineStyles[line.at( 1 )] = line;
426 else if( type == wxS( "FONTSTYLE" ) )
427 fontStyles[line.at( 1 )] = line;
428 else if( type == wxS( "PART" ) )
429 partUnits[line.at( 1 )] = ++totalUnits;
430 }
431
432 symInfo.partUnits = partUnits;
433 ksymbol->SetUnitCount( totalUnits, false );
434
435 int currentUnit = 1;
436
437 for( const nlohmann::json& line : aLines )
438 {
439 wxString type = line.at( 0 );
440
441 if( type == wxS( "PART" ) )
442 {
443 currentUnit = partUnits.at( line.at( 1 ) );
444 }
445 else if( type == wxS( "RECT" ) )
446 {
447 VECTOR2D start( line.at( 2 ), line.at( 3 ) );
448 VECTOR2D end( line.at( 4 ), line.at( 5 ) );
449 wxString styleStr = line.at( 9 );
450
451 auto rect = std::make_unique<SCH_SHAPE>( SHAPE_T::RECTANGLE, LAYER_DEVICE );
452
453 rect->SetStart( ScalePosSym( start ) );
454 rect->SetEnd( ScalePosSym( end ) );
455
456 rect->SetUnit( currentUnit );
457 ApplyLineStyle( lineStyles, rect, styleStr );
458
459 ksymbol->AddDrawItem( rect.release() );
460 }
461 else if( type == wxS( "CIRCLE" ) )
462 {
463 VECTOR2D center( line.at( 2 ), line.at( 3 ) );
464 double radius = line.at( 4 );
465 wxString styleStr = line.at( 5 );
466
467 auto circle = std::make_unique<SCH_SHAPE>( SHAPE_T::CIRCLE, LAYER_DEVICE );
468
470 circle->SetEnd( circle->GetCenter() + VECTOR2I( ScaleSize( radius ), 0 ) );
471
472 circle->SetUnit( currentUnit );
473 ApplyLineStyle( lineStyles, circle, styleStr );
474
475 ksymbol->AddDrawItem( circle.release() );
476 }
477 else if( type == wxS( "ARC" ) )
478 {
479 VECTOR2D start( line.at( 2 ), line.at( 3 ) );
480 VECTOR2D mid( line.at( 4 ), line.at( 5 ) );
481 VECTOR2D end( line.at( 6 ), line.at( 7 ) );
482 wxString styleStr = line.at( 8 );
483
484 VECTOR2D kstart = ScalePosSym( start );
485 VECTOR2D kmid = ScalePosSym( mid );
486 VECTOR2D kend = ScalePosSym( end );
487
488 auto shape = std::make_unique<SCH_SHAPE>( SHAPE_T::ARC, LAYER_DEVICE );
489
490 shape->SetArcGeometry( kstart, kmid, kend );
491
492 shape->SetUnit( currentUnit );
493 ApplyLineStyle( lineStyles, shape, styleStr );
494
495 ksymbol->AddDrawItem( shape.release() );
496 }
497 else if( type == wxS( "BEZIER" ) )
498 {
499 std::vector<double> points = line.at( 2 );
500 wxString styleStr = line.at( 3 );
501
502 std::unique_ptr<SCH_SHAPE> shape =
503 std::make_unique<SCH_SHAPE>( SHAPE_T::BEZIER, LAYER_DEVICE );
504
505 for( size_t i = 1; i < points.size(); i += 2 )
506 {
507 VECTOR2I pt = ScalePosSym( VECTOR2D( points[i - 1], points[i] ) );
508
509 switch( i )
510 {
511 case 1: shape->SetStart( pt ); break;
512 case 3: shape->SetBezierC1( pt ); break;
513 case 5: shape->SetBezierC2( pt ); break;
514 case 7: shape->SetEnd( pt ); break;
515 }
516 }
517
518 shape->SetUnit( currentUnit );
519 ApplyLineStyle( lineStyles, shape, styleStr );
520
521 ksymbol->AddDrawItem( shape.release() );
522 }
523 else if( type == wxS( "POLY" ) )
524 {
525 std::vector<double> points = line.at( 2 );
526 wxString styleStr = line.at( 4 );
527
528 auto shape = std::make_unique<SCH_SHAPE>( SHAPE_T::POLY, LAYER_DEVICE );
529
530 for( size_t i = 1; i < points.size(); i += 2 )
531 shape->AddPoint( ScalePosSym( VECTOR2D( points[i - 1], points[i] ) ) );
532
533 shape->SetUnit( currentUnit );
534 ApplyLineStyle( lineStyles, shape, styleStr );
535
536 ksymbol->AddDrawItem( shape.release() );
537 }
538 else if( type == wxS( "TEXT" ) )
539 {
540 VECTOR2D pos( line.at( 2 ), line.at( 3 ) );
541 double angle = line.at( 4 ).is_number() ? line.at( 4 ).get<double>() : 0.0;
542 wxString textStr = line.at( 5 );
543 wxString fontStyleStr = line.at( 6 );
544
545 auto text = std::make_unique<SCH_TEXT>( ScalePosSym( pos ), UnescapeHTML( textStr ),
546 LAYER_DEVICE );
547
548 text->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
549 text->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
550 text->SetTextAngleDegrees( angle );
551
552 text->SetUnit( currentUnit );
553 ApplyFontStyle( fontStyles, text, fontStyleStr );
554
555 ksymbol->AddDrawItem( text.release() );
556 }
557 else if( type == wxS( "OBJ" ) )
558 {
559 VECTOR2D start, size;
560 wxString mimeType, data;
561 //double angle = 0;
562 int upsideDown = 0;
563
564 if( line.at( 3 ).is_number() )
565 {
566 start = VECTOR2D( line.at( 3 ), line.at( 4 ) );
567 size = VECTOR2D( line.at( 5 ), line.at( 6 ) );
568 //angle = line.at( 7 );
569 upsideDown = line.at( 8 );
570
571 wxString imageUrl = line.at( 9 );
572
573 if( imageUrl.BeforeFirst( ':' ) == wxS( "data" ) )
574 {
575 wxArrayString paramsArr =
576 wxSplit( imageUrl.AfterFirst( ':' ).BeforeFirst( ',' ), ';', '\0' );
577
578 data = imageUrl.AfterFirst( ',' );
579
580 if( paramsArr.size() > 0 )
581 {
582 mimeType = paramsArr[0];
583 }
584 }
585 }
586 else if( line.at( 3 ).is_string() )
587 {
588 mimeType = line.at( 3 ).get<wxString>().BeforeFirst( ';' );
589
590 start = VECTOR2D( line.at( 4 ), line.at( 5 ) );
591 size = VECTOR2D( line.at( 6 ), line.at( 7 ) );
592 //angle = line.at( 8 );
593 data = line.at( 9 ).get<wxString>();
594 }
595
596 if( mimeType.empty() || data.empty() )
597 continue;
598
599 wxMemoryBuffer buf = wxBase64Decode( data );
600
601 if( mimeType == wxS( "image/svg+xml" ) )
602 {
603 VECTOR2D offset = ScalePosSym( start );
604
605 SVG_IMPORT_PLUGIN svgImportPlugin;
606 GRAPHICS_IMPORTER_LIB_SYMBOL libsymImporter( ksymbol, 0 );
607
608 svgImportPlugin.SetImporter( &libsymImporter );
609 svgImportPlugin.LoadFromMemory( buf );
610
611 VECTOR2D imSize( svgImportPlugin.GetImageWidth(),
612 svgImportPlugin.GetImageHeight() );
613
614 VECTOR2D pixelScale( schIUScale.IUTomm( ScaleSize( size.x ) ) / imSize.x,
615 schIUScale.IUTomm( ScaleSize( size.y ) ) / imSize.y );
616
617 if( upsideDown )
618 pixelScale.y *= -1;
619
620 libsymImporter.SetScale( pixelScale );
621
622 VECTOR2D offsetMM( schIUScale.IUTomm( offset.x ), schIUScale.IUTomm( offset.y ) );
623
624 libsymImporter.SetImportOffsetMM( offsetMM );
625
626 svgImportPlugin.Import();
627
628 // TODO: rotation
629 for( std::unique_ptr<EDA_ITEM>& item : libsymImporter.GetItems() )
630 ksymbol->AddDrawItem( static_cast<SCH_ITEM*>( item.release() ) );
631 }
632 else
633 {
634 wxMemoryInputStream memis( buf.GetData(), buf.GetDataLen() );
635
636 wxImage::SetDefaultLoadFlags( wxImage::GetDefaultLoadFlags()
637 & ~wxImage::Load_Verbose );
638 wxImage img;
639 if( img.LoadFile( memis, mimeType ) )
640 {
641 int dimMul = img.GetWidth() * img.GetHeight();
642 double maxPixels = 30000;
643
644 if( dimMul > maxPixels )
645 {
646 double scale = sqrt( maxPixels / dimMul );
647 img.Rescale( img.GetWidth() * scale, img.GetHeight() * scale );
648 }
649
650 VECTOR2D pixelScale( ScaleSize( size.x ) / img.GetWidth(),
651 ScaleSize( size.y ) / img.GetHeight() );
652
653 // TODO: rotation
654 ConvertImageToLibShapes( ksymbol, 0, img, pixelScale, ScalePosSym( start ) );
655 }
656 }
657 }
658 else if( type == wxS( "HEAD" ) )
659 {
660 symInfo.head = line;
661 }
662 else if( type == wxS( "PIN" ) )
663 {
664 wxString pinId = line.at( 1 );
665 unitParentedLines[currentUnit][pinId].push_back( line );
666 }
667 else if( type == wxS( "ATTR" ) )
668 {
669 wxString parentId = line.at( 2 );
670
671 if( parentId.empty() )
672 {
673 EASYEDAPRO::SCH_ATTR attr = line;
674 unitAttributes[currentUnit].emplace( attr.key, attr );
675 }
676 else
677 {
678 unitParentedLines[currentUnit][parentId].push_back( line );
679 }
680 }
681 }
682
685 {
686 ksymbol->SetGlobalPower();
687 ksymbol->GetReferenceField().SetText( wxS( "#PWR" ) );
688 ksymbol->GetReferenceField().SetVisible( false );
689 ksymbol->SetKeyWords( wxS( "power-flag" ) );
690 ksymbol->SetShowPinNames( false );
691 ksymbol->SetShowPinNumbers( false );
692
693 if( auto globalNetAttr = get_opt( unitAttributes[1], wxS( "Global Net Name" ) ) )
694 {
695 ApplyAttrToField( fontStyles, &ksymbol->GetValueField(), *globalNetAttr, true, true );
696
697 wxString globalNetname = globalNetAttr->value;
698
699 if( !globalNetname.empty() )
700 {
701 ksymbol->SetDescription( wxString::Format(
702 _( "Power symbol creates a global label with name '%s'" ),
703 globalNetname ) );
704 }
705 }
706 }
707 else
708 {
709 auto designatorAttr = get_opt( unitAttributes[1], wxS( "Designator" ) );
710
711 if( designatorAttr && !designatorAttr->value.empty() )
712 {
713 wxString symbolPrefix = designatorAttr->value;
714
715 if( symbolPrefix.EndsWith( wxS( "?" ) ) )
716 symbolPrefix.RemoveLast();
717
718 ksymbol->GetReferenceField().SetText( symbolPrefix );
719 }
720
721 for( const wxString& attrName : c_attributesWhitelist )
722 {
723 if( auto valOpt = get_opt( aDeviceAttributes, attrName ) )
724 {
725 if( valOpt->empty() )
726 continue;
727
728 SCH_FIELD* fd = ksymbol->FindFieldCaseInsensitive( attrName );
729
730 if( !fd )
731 {
732 fd = new SCH_FIELD( ksymbol, FIELD_T::USER, attrName );
733 ksymbol->AddField( fd );
734 }
735
736 wxString value = *valOpt;
737
738 value.Replace( wxS( "\u2103" ), wxS( "\u00B0C" ), true ); // ℃ -> °C
739
740 fd->SetText( value );
741 fd->SetVisible( false );
742 }
743 }
744 }
745
746 for( auto& [unitId, parentedLines] : unitParentedLines )
747 {
748 for( auto& [pinId, lines] : parentedLines )
749 {
750 std::optional<EASYEDAPRO::SYM_PIN> epin;
751 std::map<wxString, EASYEDAPRO::SCH_ATTR> pinAttributes;
752
753 for( const nlohmann::json& line : lines )
754 {
755 wxString type = line.at( 0 );
756
757 if( type == wxS( "ATTR" ) )
758 {
759 EASYEDAPRO::SCH_ATTR attr = line;
760 pinAttributes.emplace( attr.key, attr );
761 }
762 else if( type == wxS( "PIN" ) )
763 {
764 epin = line;
765 }
766 }
767
768 if( !epin )
769 continue;
770
771 EASYEDAPRO::PIN_INFO pinInfo;
772 pinInfo.pin = *epin;
773
774 std::unique_ptr<SCH_PIN> pin = std::make_unique<SCH_PIN>( ksymbol );
775
776 pin->SetUnit( unitId );
777
778 pin->SetLength( ScaleSize( epin->length ) );
779 pin->SetPosition( ScalePosSym( epin->position ) );
780
781 PIN_ORIENTATION orient = PIN_ORIENTATION::PIN_RIGHT;
782
783 if( epin->rotation == 0 )
784 orient = PIN_ORIENTATION::PIN_RIGHT;
785 if( epin->rotation == 90 )
786 orient = PIN_ORIENTATION::PIN_UP;
787 if( epin->rotation == 180 )
788 orient = PIN_ORIENTATION::PIN_LEFT;
789 if( epin->rotation == 270 )
790 orient = PIN_ORIENTATION::PIN_DOWN;
791
792 pin->SetOrientation( orient );
793
795 {
796 pin->SetName( ksymbol->GetName() );
797 //pin->SetVisible( false );
798 }
799 else if( auto pinNameAttr = get_opt( pinAttributes, "NAME" ) )
800 {
801 pin->SetName( pinNameAttr->value );
802 pinInfo.name = pinNameAttr->value;
803
804 if( !pinNameAttr->valVisible )
805 pin->SetNameTextSize( schIUScale.MilsToIU( 1 ) );
806 }
807
808 if( auto pinNumAttr = get_opt( pinAttributes, "NUMBER" ) )
809 {
810 pin->SetNumber( pinNumAttr->value );
811 pinInfo.number = pinNumAttr->value;
812
813 if( !pinNumAttr->valVisible )
814 pin->SetNumberTextSize( schIUScale.MilsToIU( 1 ) );
815 }
816
818 {
819 pin->SetType( ELECTRICAL_PINTYPE::PT_POWER_IN );
820 }
821 else if( auto pinTypeAttr = get_opt( pinAttributes, "Pin Type" ) )
822 {
823 if( pinTypeAttr->value == wxS( "IN" ) )
824 pin->SetType( ELECTRICAL_PINTYPE::PT_INPUT );
825 if( pinTypeAttr->value == wxS( "OUT" ) )
826 pin->SetType( ELECTRICAL_PINTYPE::PT_OUTPUT );
827 if( pinTypeAttr->value == wxS( "BI" ) )
828 pin->SetType( ELECTRICAL_PINTYPE::PT_BIDI );
829 }
830
831 if( get_opt( pinAttributes, "NO_CONNECT" ) )
832 pin->SetType( ELECTRICAL_PINTYPE::PT_NC );
833
834 if( pin->GetNumberTextSize() * int( pin->GetNumber().size() ) > pin->GetLength() )
835 pin->SetNumberTextSize( pin->GetLength() / pin->GetNumber().size() );
836
837 symInfo.pins.push_back( pinInfo );
838 ksymbol->AddDrawItem( pin.release() );
839 }
840 }
841
842 symInfo.symbolAttr = get_opt( unitAttributes[1], "Symbol" ); // TODO: per-unit
843
844 /*BOX2I bbox = ksymbol->GetBodyBoundingBox( 0, 0, true, true );
845 bbox.Inflate( schIUScale.MilsToIU( 10 ) );*/
846
847 /*ksymbol->GetReferenceField().SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM );
848 ksymbol->GetReferenceField().SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
849 ksymbol->GetReferenceField().SetPosition( VECTOR2I( bbox.GetCenter().x, -bbox.GetTop() ) );
850
851 ksymbol->GetValueField().SetVertJustify( GR_TEXT_V_ALIGN_TOP );
852 ksymbol->GetValueField().SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
853 ksymbol->GetValueField().SetPosition( VECTOR2I( bbox.GetCenter().x, -bbox.GetBottom() ) );*/
854
855 symInfo.libSymbol = std::move( ksymbolPtr );
856
857 return symInfo;
858}
859
860
862 const nlohmann::json& aProject,
863 std::map<wxString, EASYEDAPRO::SYM_INFO>& aSymbolMap,
864 const std::map<wxString, EASYEDAPRO::BLOB>& aBlobMap,
865 const std::vector<nlohmann::json>& aLines,
866 const wxString& aLibName )
867{
868 std::vector<std::unique_ptr<SCH_ITEM>> createdItems;
869
870 std::map<wxString, std::vector<nlohmann::json>> parentedLines;
871 std::map<wxString, std::vector<nlohmann::json>> ruleLines;
872
873 std::map<wxString, nlohmann::json> lineStyles;
874 std::map<wxString, nlohmann::json> fontStyles;
875
876 for( const nlohmann::json& line : aLines )
877 {
878 wxString type = line.at( 0 );
879
880 if( type == wxS( "LINESTYLE" ) )
881 lineStyles[line.at( 1 )] = line;
882 else if( type == wxS( "FONTSTYLE" ) )
883 fontStyles[line.at( 1 )] = line;
884 }
885
886 for( const nlohmann::json& line : aLines )
887 {
888 wxString type = line.at( 0 );
889
890 if( type == wxS( "RECT" ) )
891 {
892 VECTOR2D start( line.at( 2 ), line.at( 3 ) );
893 VECTOR2D end( line.at( 4 ), line.at( 5 ) );
894 wxString styleStr = line.at( 9 );
895
896 std::unique_ptr<SCH_SHAPE> rect = std::make_unique<SCH_SHAPE>( SHAPE_T::RECTANGLE );
897
898 rect->SetStart( ScalePos( start ) );
899 rect->SetEnd( ScalePos( end ) );
900
901 ApplyLineStyle( lineStyles, rect, styleStr );
902
903 createdItems.push_back( std::move( rect ) );
904 }
905 else if( type == wxS( "CIRCLE" ) )
906 {
907 VECTOR2D center( line.at( 2 ), line.at( 3 ) );
908 double radius = line.at( 4 );
909 wxString styleStr = line.at( 5 );
910
911 std::unique_ptr<SCH_SHAPE> circle = std::make_unique<SCH_SHAPE>( SHAPE_T::CIRCLE );
912
914 circle->SetEnd( circle->GetCenter() + VECTOR2I( ScaleSize( radius ), 0 ) );
915
916 ApplyLineStyle( lineStyles, circle, styleStr );
917
918 createdItems.push_back( std::move( circle ) );
919 }
920 else if( type == wxS( "POLY" ) )
921 {
922 std::vector<double> points = line.at( 2 );
923 wxString styleStr = line.at( 4 );
924
926
927 for( size_t i = 1; i < points.size(); i += 2 )
928 chain.Append( ScalePos( VECTOR2D( points[i - 1], points[i] ) ) );
929
930 for( int segId = 0; segId < chain.SegmentCount(); segId++ )
931 {
932 const SEG& seg = chain.CSegment( segId );
933
934 std::unique_ptr<SCH_LINE> schLine =
935 std::make_unique<SCH_LINE>( seg.A, LAYER_NOTES );
936 schLine->SetEndPoint( seg.B );
937
938 ApplyLineStyle( lineStyles, schLine, styleStr );
939
940 createdItems.push_back( std::move( schLine ) );
941 }
942 }
943 else if( type == wxS( "TEXT" ) )
944 {
945 VECTOR2D pos( line.at( 2 ), line.at( 3 ) );
946 double angle = line.at( 4 ).is_number() ? line.at( 4 ).get<double>() : 0.0;
947 wxString textStr = line.at( 5 );
948 wxString fontStyleStr = line.at( 6 );
949
950 std::unique_ptr<SCH_TEXT> text =
951 std::make_unique<SCH_TEXT>( ScalePos( pos ), UnescapeHTML( textStr ) );
952
953 text->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
954 text->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
955
956 text->SetTextAngleDegrees( angle );
957
958 ApplyFontStyle( fontStyles, text, fontStyleStr );
959
960 createdItems.push_back( std::move( text ) );
961 }
962 else if( type == wxS( "OBJ" ) )
963 {
964 VECTOR2D start, size;
965 wxString mimeType, base64Data;
966 double angle = 0;
967 int flipped = 0;
968
969 if( line.at( 3 ).is_number() )
970 {
971 start = VECTOR2D( line.at( 3 ), line.at( 4 ) );
972 size = VECTOR2D( line.at( 5 ), line.at( 6 ) );
973 angle = line.at( 7 );
974 flipped = line.at( 8 );
975
976 wxString imageUrl = line.at( 9 );
977
978 if( imageUrl.BeforeFirst( ':' ) == wxS( "data" ) )
979 {
980 wxArrayString paramsArr =
981 wxSplit( imageUrl.AfterFirst( ':' ).BeforeFirst( ',' ), ';', '\0' );
982
983 base64Data = imageUrl.AfterFirst( ',' );
984
985 if( paramsArr.size() > 0 )
986 mimeType = paramsArr[0];
987 }
988 else if( imageUrl.BeforeFirst( ':' ) == wxS( "blob" ) )
989 {
990 wxString objectId = imageUrl.AfterLast( ':' );
991
992 if( auto blob = get_opt( aBlobMap, objectId ) )
993 {
994 wxString blobUrl = blob->url;
995
996 if( blobUrl.BeforeFirst( ':' ) == wxS( "data" ) )
997 {
998 wxArrayString paramsArr = wxSplit(
999 blobUrl.AfterFirst( ':' ).BeforeFirst( ',' ), ';', '\0' );
1000
1001 base64Data = blobUrl.AfterFirst( ',' );
1002
1003 if( paramsArr.size() > 0 )
1004 mimeType = paramsArr[0];
1005 }
1006 }
1007 }
1008 }
1009 else if( line.at( 3 ).is_string() )
1010 {
1011 mimeType = line.at( 3 ).get<wxString>().BeforeFirst( ';' );
1012
1013 start = VECTOR2D( line.at( 4 ), line.at( 5 ) );
1014 size = VECTOR2D( line.at( 6 ), line.at( 7 ) );
1015 angle = line.at( 8 );
1016 base64Data = line.at( 9 ).get<wxString>();
1017 }
1018
1019 VECTOR2D kstart = ScalePos( start );
1020 VECTOR2D ksize = ScaleSize( size );
1021
1022 if( mimeType.empty() || base64Data.empty() )
1023 continue;
1024
1025 wxMemoryBuffer buf = wxBase64Decode( base64Data );
1026
1027 if( mimeType == wxS( "image/svg+xml" ) )
1028 {
1029 SVG_IMPORT_PLUGIN svgImportPlugin;
1030 GRAPHICS_IMPORTER_SCH schImporter;
1031
1032 svgImportPlugin.SetImporter( &schImporter );
1033 svgImportPlugin.LoadFromMemory( buf );
1034
1035 VECTOR2D imSize( svgImportPlugin.GetImageWidth(),
1036 svgImportPlugin.GetImageHeight() );
1037
1038 VECTOR2D pixelScale( schIUScale.IUTomm( ScaleSize( size.x ) ) / imSize.x,
1039 schIUScale.IUTomm( ScaleSize( size.y ) ) / imSize.y );
1040
1041 schImporter.SetScale( pixelScale );
1042
1043 VECTOR2D offsetMM( schIUScale.IUTomm( kstart.x ), schIUScale.IUTomm( kstart.y ) );
1044
1045 schImporter.SetImportOffsetMM( offsetMM );
1046
1047 svgImportPlugin.Import();
1048
1049 for( std::unique_ptr<EDA_ITEM>& item : schImporter.GetItems() )
1050 {
1051 SCH_ITEM* schItem = static_cast<SCH_ITEM*>( item.release() );
1052
1053 for( double i = angle; i > 0; i -= 90 )
1054 {
1055 if( schItem->Type() == SCH_LINE_T )
1056 {
1057 // Lines need special handling for some reason
1058 schItem->SetFlags( STARTPOINT );
1059 schItem->Rotate( kstart, false );
1060 schItem->ClearFlags( STARTPOINT );
1061
1062 schItem->SetFlags( ENDPOINT );
1063 schItem->Rotate( kstart, false );
1064 schItem->ClearFlags( ENDPOINT );
1065 }
1066 else
1067 {
1068 schItem->Rotate( kstart, false );
1069 }
1070 }
1071
1072 if( flipped )
1073 {
1074 // Lines need special handling for some reason
1075 if( schItem->Type() == SCH_LINE_T )
1076 schItem->SetFlags( STARTPOINT | ENDPOINT );
1077
1078 schItem->MirrorHorizontally( kstart.x );
1079
1080 if( schItem->Type() == SCH_LINE_T )
1081 schItem->ClearFlags( STARTPOINT | ENDPOINT );
1082 }
1083
1084 createdItems.emplace_back( schItem );
1085 }
1086 }
1087 else
1088 {
1089 std::unique_ptr<SCH_BITMAP> bitmap = std::make_unique<SCH_BITMAP>();
1090 REFERENCE_IMAGE& refImage = bitmap->GetReferenceImage();
1091
1092 wxImage::SetDefaultLoadFlags( wxImage::GetDefaultLoadFlags()
1093 & ~wxImage::Load_Verbose );
1094
1095 if( refImage.ReadImageFile( buf ) )
1096 {
1097 VECTOR2D kcenter = kstart + ksize / 2;
1098
1099 double scaleFactor = ScaleSize( size.x ) / refImage.GetSize().x;
1100 refImage.SetImageScale( scaleFactor );
1101 bitmap->SetPosition( kcenter );
1102
1103 for( double i = angle; i > 0; i -= 90 )
1104 bitmap->Rotate( kstart, false );
1105
1106 if( flipped )
1107 bitmap->MirrorHorizontally( kstart.x );
1108
1109 createdItems.push_back( std::move( bitmap ) );
1110 }
1111 }
1112 }
1113 if( type == wxS( "WIRE" ) )
1114 {
1115 wxString wireId = line.at( 1 );
1116 parentedLines[wireId].push_back( line );
1117 }
1118 else if( type == wxS( "COMPONENT" ) )
1119 {
1120 wxString compId = line.at( 1 );
1121 parentedLines[compId].push_back( line );
1122 }
1123 else if( type == wxS( "ATTR" ) )
1124 {
1125 wxString compId = line.at( 2 );
1126 parentedLines[compId].push_back( line );
1127 }
1128 }
1129
1130 for( auto& [parentId, lines] : parentedLines )
1131 {
1132 std::optional<EASYEDAPRO::SCH_COMPONENT> component;
1133 std::optional<EASYEDAPRO::SCH_WIRE> wire;
1134 std::map<wxString, EASYEDAPRO::SCH_ATTR> attributes;
1135
1136 for( const nlohmann::json& line : lines )
1137 {
1138 if( line.at( 0 ) == "COMPONENT" )
1139 {
1140 component = line;
1141 }
1142 else if( line.at( 0 ) == "WIRE" )
1143 {
1144 wire = line;
1145 }
1146 else if( line.at( 0 ) == "ATTR" )
1147 {
1148 EASYEDAPRO::SCH_ATTR attr = line;
1149 attributes.emplace( attr.key, attr );
1150 }
1151 }
1152
1153 if( component )
1154 {
1155 auto deviceAttr = get_opt( attributes, "Device" );
1156 auto symbolAttr = get_opt( attributes, "Symbol" );
1157
1158 if( !deviceAttr )
1159 continue;
1160
1161 std::map<wxString, wxString> compAttrs = EASYEDAPRO::AnyMapToStringMap(
1162 aProject.at( "devices" ).at( deviceAttr->value ).at( "attributes" ) );
1163
1164 wxString symbolId;
1165
1166 if( symbolAttr && !symbolAttr->value.IsEmpty() )
1167 symbolId = symbolAttr->value;
1168 else
1169 symbolId = compAttrs.at( "Symbol" );
1170
1171 auto it = aSymbolMap.find( symbolId );
1172 if( it == aSymbolMap.end() )
1173 {
1174 wxLogError( "Symbol of '%s' with uuid '%s' not found.", component->name, symbolId );
1175 continue;
1176 }
1177
1178 EASYEDAPRO::SYM_INFO& esymInfo = it->second;
1179 LIB_SYMBOL newLibSymbol = *esymInfo.libSymbol.get();
1180
1181 wxString unitName = component->name;
1182
1183 LIB_ID libId = EASYEDAPRO::ToKiCadLibID( aLibName,
1184 newLibSymbol.GetLibId().GetLibItemName() );
1185
1186 auto schSym = std::make_unique<SCH_SYMBOL>( newLibSymbol, libId,
1187 &aSchematic->CurrentSheet(),
1188 esymInfo.partUnits[unitName] );
1189
1190 schSym->SetFootprintFieldText( newLibSymbol.GetFootprint() );
1191
1192 for( double i = component->rotation; i > 0; i -= 90 )
1193 schSym->Rotate( VECTOR2I(), true );
1194
1195 if( component->mirror )
1196 schSym->MirrorHorizontally( 0 );
1197
1198 schSym->SetPosition( ScalePos( component->position ) );
1199
1201 {
1202 if( auto globalNetAttr = get_opt( attributes, "Global Net Name" ) )
1203 {
1204 ApplyAttrToField( fontStyles, schSym->GetField( FIELD_T::VALUE ),
1205 *globalNetAttr, false, true, compAttrs, schSym.get() );
1206
1207 for( SCH_PIN* pin : schSym->GetAllLibPins() )
1208 pin->SetName( globalNetAttr->value );
1209 }
1210 else if( auto nameAttr = get_opt( attributes, "Name" ) )
1211 {
1212 ApplyAttrToField( fontStyles, schSym->GetField( FIELD_T::VALUE ),
1213 *nameAttr, false, true, compAttrs, schSym.get() );
1214
1215 for( SCH_PIN* pin : schSym->GetAllLibPins() )
1216 pin->SetName( nameAttr->value );
1217 }
1218 else
1219 {
1220 SCH_FIELD* valueField = schSym->GetField( FIELD_T::VALUE );
1221 valueField->SetText( newLibSymbol.GetValueField().GetText() );
1222 }
1223
1224 schSym->SetRef( &aSchematic->CurrentSheet(), wxS( "#PWR?" ) );
1225 schSym->GetField( FIELD_T::REFERENCE )->SetVisible( false );
1226 }
1227 else if( esymInfo.head.symbolType == EASYEDAPRO::SYMBOL_TYPE::NETPORT )
1228 {
1229 auto nameAttr = get_opt( attributes, "Name" );
1230
1231 wxString netName;
1232
1233 if( nameAttr && !nameAttr->value.IsEmpty() )
1234 netName = nameAttr->value;
1235 else
1236 netName = compAttrs.at( "Name" );
1237
1238 std::unique_ptr<SCH_GLOBALLABEL> label = std::make_unique<SCH_GLOBALLABEL>(
1239 ScalePos( component->position ), netName );
1240
1241 std::vector<SCH_PIN*> pins = schSym->GetPins( &aSchematic->CurrentSheet() );
1242
1243 if( pins.size() > 0 )
1244 {
1245 switch( pins[0]->GetType() )
1246 {
1247 case ELECTRICAL_PINTYPE::PT_INPUT:
1248 label->SetShape( LABEL_FLAG_SHAPE::L_INPUT );
1249 break;
1250 case ELECTRICAL_PINTYPE::PT_OUTPUT:
1251 label->SetShape( LABEL_FLAG_SHAPE::L_OUTPUT );
1252 break;
1253 case ELECTRICAL_PINTYPE::PT_BIDI:
1254 label->SetShape( LABEL_FLAG_SHAPE::L_BIDI );
1255 break;
1256 default: break;
1257 }
1258 }
1259
1260 BOX2I bbox = schSym->GetBodyAndPinsBoundingBox();
1261 bbox.Offset( -schSym->GetPosition() );
1262 VECTOR2I bboxCenter = bbox.GetCenter();
1263
1265
1266 if( std::abs( bboxCenter.x ) >= std::abs( bboxCenter.y ) )
1267 {
1268 if( bboxCenter.x >= 0 )
1269 spin = SPIN_STYLE::RIGHT;
1270 else
1271 spin = SPIN_STYLE::LEFT;
1272 }
1273 else
1274 {
1275 if( bboxCenter.y >= 0 )
1276 spin = SPIN_STYLE::BOTTOM;
1277 else
1278 spin = SPIN_STYLE::UP;
1279 }
1280
1281 label->SetSpinStyle( spin );
1282
1283 if( nameAttr )
1284 {
1285 nlohmann::json style = fontStyles[nameAttr->fontStyle];
1286
1287 if( !style.is_null() && style.at( 5 ).is_number() )
1288 {
1289 double size = style.at( 5 ).get<double>() * 0.5;
1290 label->SetTextSize( VECTOR2I( ScaleSize( size ), ScaleSize( size ) ) );
1291 }
1292 }
1293
1294 createdItems.push_back( std::move( label ) );
1295
1296 continue;
1297 }
1298 else
1299 {
1300 for( const wxString& attrKey : c_attributesWhitelist )
1301 {
1302 if( auto valOpt = get_opt( compAttrs, attrKey ) )
1303 {
1304 if( valOpt->empty() )
1305 continue;
1306
1307 SCH_FIELD* text = schSym->FindFieldCaseInsensitive( attrKey );
1308
1309 if( !text )
1310 {
1311 text = new SCH_FIELD( schSym.get(), FIELD_T::USER, attrKey );
1312 schSym->AddField( text );
1313 }
1314
1315 wxString value = *valOpt;
1316
1317 value.Replace( wxS( "\u2103" ), wxS( "\u00B0C" ), true ); // ℃ -> °C
1318
1319 text->SetText( value );
1320 text->SetVisible( false );
1321 }
1322 }
1323
1324 auto nameAttr = get_opt( attributes, "Name" );
1325 auto valueAttr = get_opt( attributes, "Value" );
1326
1327 if( valueAttr && valueAttr->value.empty() )
1328 valueAttr->value = get_def( compAttrs, "Value", wxString() );
1329
1330 if( nameAttr && nameAttr->value.empty() )
1331 nameAttr->value = get_def( compAttrs, "Name", wxString() );
1332
1333 std::optional<EASYEDAPRO::SCH_ATTR> targetValueAttr;
1334
1335 if( valueAttr && !valueAttr->value.empty() && valueAttr->valVisible )
1336 targetValueAttr = valueAttr;
1337 else if( nameAttr && !nameAttr->value.empty() && nameAttr->valVisible )
1338 targetValueAttr = nameAttr;
1339 else if( valueAttr && !valueAttr->value.empty() )
1340 targetValueAttr = valueAttr;
1341 else if( nameAttr && !nameAttr->value.empty() )
1342 targetValueAttr = nameAttr;
1343
1344 if( targetValueAttr )
1345 {
1346 ApplyAttrToField( fontStyles, schSym->GetField( FIELD_T::VALUE ),
1347 *targetValueAttr, false, true, compAttrs, schSym.get() );
1348 }
1349
1350 if( auto descrAttr = get_opt( attributes, "Description" ) )
1351 {
1352 ApplyAttrToField( fontStyles, schSym->GetField( FIELD_T::DESCRIPTION ),
1353 *descrAttr, false, true, compAttrs, schSym.get() );
1354 }
1355
1356 if( auto designatorAttr = get_opt( attributes, "Designator" ) )
1357 {
1358 ApplyAttrToField( fontStyles, schSym->GetField( FIELD_T::REFERENCE ),
1359 *designatorAttr, false, true, compAttrs, schSym.get() );
1360
1361 schSym->SetRef( &aSchematic->CurrentSheet(), designatorAttr->value );
1362 }
1363
1364 for( auto& [attrKey, attr] : attributes )
1365 {
1366 if( attrKey == wxS( "Name" ) || attrKey == wxS( "Value" )
1367 || attrKey == wxS( "Global Net Name" ) || attrKey == wxS( "Designator" )
1368 || attrKey == wxS( "Description" ) || attrKey == wxS( "Device" )
1369 || attrKey == wxS( "Footprint" ) || attrKey == wxS( "Symbol" )
1370 || attrKey == wxS( "Unique ID" ) )
1371 {
1372 continue;
1373 }
1374
1375 if( attr.value.IsEmpty() )
1376 continue;
1377
1378 SCH_FIELD* text = schSym->FindFieldCaseInsensitive( attrKey );
1379
1380 if( !text )
1381 {
1382 text = new SCH_FIELD( schSym.get(), FIELD_T::USER, attrKey );
1383 schSym->AddField( text );
1384 }
1385
1386 text->SetPosition( schSym->GetPosition() );
1387
1388 ApplyAttrToField( fontStyles, text, attr, false, true, compAttrs,
1389 schSym.get() );
1390 }
1391 }
1392
1393 for( const EASYEDAPRO::PIN_INFO& pinInfo : esymInfo.pins )
1394 {
1395 wxString pinKey = parentId + pinInfo.pin.id;
1396 auto pinLines = get_opt( parentedLines, pinKey );
1397
1398 if( !pinLines )
1399 continue;
1400
1401 for( const nlohmann::json& pinLine : *pinLines )
1402 {
1403 if( pinLine.at( 0 ) != "ATTR" )
1404 continue;
1405
1406 EASYEDAPRO::SCH_ATTR attr = pinLine;
1407
1408 if( attr.key != wxS( "NO_CONNECT" ) )
1409 continue;
1410
1411 if( SCH_PIN* schPin = schSym->GetPin( pinInfo.number ) )
1412 {
1413 VECTOR2I pos = schSym->GetPinPhysicalPosition( schPin->GetLibPin() );
1414
1415 std::unique_ptr<SCH_NO_CONNECT> noConn =
1416 std::make_unique<SCH_NO_CONNECT>( pos );
1417
1418 createdItems.push_back( std::move( noConn ) );
1419 }
1420 }
1421 }
1422
1423 createdItems.push_back( std::move( schSym ) );
1424 }
1425 else // Not component
1426 {
1427 std::vector<SHAPE_LINE_CHAIN> wireLines;
1428
1429 if( wire )
1430 {
1431 for( const std::vector<double>& ptArr : wire->geometry )
1432 {
1434
1435 for( size_t i = 1; i < ptArr.size(); i += 2 )
1436 chain.Append( ScalePos( VECTOR2D( ptArr[i - 1], ptArr[i] ) ) );
1437
1438 if( chain.PointCount() < 2 )
1439 continue;
1440
1441 wireLines.push_back( chain );
1442
1443 for( int segId = 0; segId < chain.SegmentCount(); segId++ )
1444 {
1445 const SEG& seg = chain.CSegment( segId );
1446
1447 std::unique_ptr<SCH_LINE> schLine =
1448 std::make_unique<SCH_LINE>( seg.A, LAYER_WIRE );
1449 schLine->SetEndPoint( seg.B );
1450
1451 createdItems.push_back( std::move( schLine ) );
1452 }
1453 }
1454 }
1455
1456 auto netAttr = get_opt( attributes, "NET" );
1457
1458 if( netAttr )
1459 {
1460 if( !netAttr->valVisible || netAttr->value.IsEmpty() )
1461 continue;
1462
1463 VECTOR2I kpos = ScalePos( *netAttr->position );
1464 VECTOR2I nearestPos = kpos;
1465 SEG::ecoord min_dist_sq = VECTOR2I::ECOORD_MAX;
1466
1467 for( const SHAPE_LINE_CHAIN& chain : wireLines )
1468 {
1469 VECTOR2I nearestPt = chain.NearestPoint( kpos, false );
1470 SEG::ecoord dist_sq = ( nearestPt - kpos ).SquaredEuclideanNorm();
1471
1472 if( dist_sq < min_dist_sq )
1473 {
1474 min_dist_sq = dist_sq;
1475 nearestPos = nearestPt;
1476 }
1477 }
1478
1479 std::unique_ptr<SCH_LABEL> label = std::make_unique<SCH_LABEL>();
1480
1481 label->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
1482 label->SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM );
1483
1484 for( double i = netAttr->rotation; i > 0; i -= 90 )
1485 label->Rotate90( true );
1486
1487 label->SetPosition( nearestPos );
1488 label->SetText( netAttr->value );
1489
1490 ApplyFontStyle( fontStyles, label, netAttr->fontStyle );
1491
1492 createdItems.push_back( std::move( label ) );
1493 }
1494 }
1495 }
1496
1497 // Adjust page to content
1498 BOX2I sheetBBox;
1499
1500 for( std::unique_ptr<SCH_ITEM>& ptr : createdItems )
1501 {
1502 if( ptr->Type() == SCH_SYMBOL_T )
1503 sheetBBox.Merge( static_cast<SCH_SYMBOL*>( ptr.get() )->GetBodyAndPinsBoundingBox() );
1504 else
1505 sheetBBox.Merge( ptr->GetBoundingBox() );
1506 }
1507
1508 SCH_SCREEN* screen = aRootSheet->GetScreen();
1509 PAGE_INFO pageInfo = screen->GetPageSettings();
1510
1511 int alignGrid = schIUScale.MilsToIU( 50 );
1512
1513 VECTOR2D offset( -sheetBBox.GetLeft(), -sheetBBox.GetTop() );
1514 offset.x = KiROUND( offset.x / alignGrid ) * alignGrid;
1515 offset.y = KiROUND( offset.y / alignGrid ) * alignGrid;
1516
1517 pageInfo.SetWidthMils( schIUScale.IUToMils( sheetBBox.GetWidth() ) );
1518 pageInfo.SetHeightMils( schIUScale.IUToMils( sheetBBox.GetHeight() ) );
1519
1520 screen->SetPageSettings( pageInfo );
1521
1522 for( std::unique_ptr<SCH_ITEM>& ptr : createdItems )
1523 {
1524 ptr->Move( offset );
1525 screen->Append( ptr.release() );
1526 }
1527}
int color
Definition: DXF_plotter.cpp:63
constexpr EDA_IU_SCALE schIUScale
Definition: base_units.h:114
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:142
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:110
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: eda_item.h:144
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:97
virtual void SetVisible(bool aVisible)
Definition: eda_text.cpp:386
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:147
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:85
const LIB_ID & GetLibId() const override
Definition: lib_symbol.h:155
void SetGlobalPower()
Definition: lib_symbol.cpp:475
void SetUnitCount(int aCount, bool aDuplicateDrawItems=true)
Set the units per symbol count.
wxString GetFootprint() override
For items with footprint fields.
Definition: lib_symbol.h:196
SCH_FIELD * FindFieldCaseInsensitive(const wxString &aFieldName)
wxString GetName() const override
Definition: lib_symbol.h:149
void SetDescription(const wxString &aDescription)
Gets the Description field text value *‍/.
Definition: lib_symbol.h:164
void SetKeyWords(const wxString &aKeyWords)
Definition: lib_symbol.h:181
SCH_FIELD & GetValueField()
Return reference to the value field.
Definition: lib_symbol.h:334
void AddField(SCH_FIELD *aField)
Add a field.
Definition: lib_symbol.cpp:993
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:785
SCH_FIELD & GetReferenceField()
Return reference to the reference designator field.
Definition: lib_symbol.h:338
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:262
void SetWidthMils(double aWidthInMils)
Definition: page_info.cpp:248
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:88
SCH_SHEET_PATH & CurrentSheet() const
Definition: schematic.h:171
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)
void SetText(const wxString &aText) override
Definition: sch_field.cpp:1089
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:168
virtual void MirrorHorizontally(int aCenter)
Mirror item horizontally about aCenter.
Definition: sch_item.h:377
virtual void Rotate(const VECTOR2I &aCenter, bool aRotateCCW)
Rotate the item around aCenter 90 degrees in the clockwise direction.
Definition: sch_item.h:394
const PAGE_INFO & GetPageSettings() const
Definition: sch_screen.h:139
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Definition: sch_screen.cpp:160
void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition: sch_screen.h:140
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:47
SCH_SCREEN * GetScreen() const
Definition: sch_sheet.h:116
Schematic symbol object.
Definition: sch_symbol.h:75
BOX2I GetBodyAndPinsBoundingBox() const override
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
const VECTOR2I GetCenter() const
Definition: shape_circle.h:123
void SetCenter(const VECTOR2I &aCenter)
Definition: shape_circle.h:113
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.
const VECTOR2I NearestPoint(const VECTOR2I &aP, bool aAllowInternalShapePoints=true) const
Find a point on the line chain that is closest to point aP.
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:94
void SetLineStyle(LINE_STYLE aLineStyle)
void SetWidth(int aWidth)
void SetColor(const KIGFX::COLOR4D &aColor)
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:164
virtual void SetShowPinNames(bool aShow)
Set or clear the pin name visibility flag.
Definition: symbol.h:158
static constexpr extended_type ECOORD_MAX
Definition: vector2d.h:76
#define _(s)
static constexpr EDA_ANGLE ANGLE_VERTICAL
Definition: eda_angle.h:408
static constexpr EDA_ANGLE ANGLE_HORIZONTAL
Definition: eda_angle.h:407
#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:456
@ LAYER_WIRE
Definition: layer_ids.h:442
@ LAYER_NOTES
Definition: layer_ids.h:457
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:400
PIN_ORIENTATION
The symbol library pin object orientations.
Definition: pin_type.h:105
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)
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:90
constexpr int IUToMils(int iu) const
Definition: base_units.h:103
constexpr int MilsToIU(int mils) const
Definition: base_units.h:97
@ SYM_ORIENT_270
Definition: symbol.h:42
@ SYM_MIRROR_Y
Definition: symbol.h:44
@ SYM_ORIENT_180
Definition: symbol.h:41
@ SYM_MIRROR_X
Definition: symbol.h:43
@ SYM_ORIENT_90
Definition: symbol.h:40
@ SYM_ORIENT_0
Definition: symbol.h:39
VECTOR2I center
const SHAPE_LINE_CHAIN chain
int radius
VECTOR2I end
SHAPE_CIRCLE circle(c.m_circle_center, c.m_circle_radius)
GR_TEXT_H_ALIGN_T
This is API surface mapped to common.types.HorizontalAlignment.
@ GR_TEXT_H_ALIGN_CENTER
@ GR_TEXT_H_ALIGN_RIGHT
@ GR_TEXT_H_ALIGN_LEFT
GR_TEXT_V_ALIGN_T
This is API surface mapped to common.types.VertialAlignment.
@ GR_TEXT_V_ALIGN_BOTTOM
@ GR_TEXT_V_ALIGN_CENTER
@ GR_TEXT_V_ALIGN_TOP
@ SCH_LINE_T
Definition: typeinfo.h:164
@ SCH_SYMBOL_T
Definition: typeinfo.h:173
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:695
VECTOR2< double > VECTOR2D
Definition: vector2d.h:694