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( "POLY" ) )
494 {
495 std::vector<double> points = line.at( 2 );
496 wxString styleStr = line.at( 4 );
497
498 auto shape = std::make_unique<SCH_SHAPE>( SHAPE_T::POLY, LAYER_DEVICE );
499
500 for( size_t i = 1; i < points.size(); i += 2 )
501 shape->AddPoint( ScalePosSym( VECTOR2D( points[i - 1], points[i] ) ) );
502
503 shape->SetUnit( currentUnit );
504 ApplyLineStyle( lineStyles, shape, styleStr );
505
506 ksymbol->AddDrawItem( shape.release() );
507 }
508 else if( type == wxS( "TEXT" ) )
509 {
510 VECTOR2D pos( line.at( 2 ), line.at( 3 ) );
511 double angle = line.at( 4 );
512 wxString textStr = line.at( 5 );
513 wxString fontStyleStr = line.at( 6 );
514
515 auto text = std::make_unique<SCH_TEXT>( ScalePosSym( pos ), UnescapeHTML( textStr ),
516 LAYER_DEVICE );
517
518 text->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
519 text->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
520 text->SetTextAngleDegrees( angle );
521
522 text->SetUnit( currentUnit );
523 ApplyFontStyle( fontStyles, text, fontStyleStr );
524
525 ksymbol->AddDrawItem( text.release() );
526 }
527 else if( type == wxS( "OBJ" ) )
528 {
529 VECTOR2D start, size;
530 wxString mimeType, data;
531 //double angle = 0;
532 int upsideDown = 0;
533
534 if( line.at( 3 ).is_number() )
535 {
536 start = VECTOR2D( line.at( 3 ), line.at( 4 ) );
537 size = VECTOR2D( line.at( 5 ), line.at( 6 ) );
538 //angle = line.at( 7 );
539 upsideDown = line.at( 8 );
540
541 wxString imageUrl = line.at( 9 );
542
543 if( imageUrl.BeforeFirst( ':' ) == wxS( "data" ) )
544 {
545 wxArrayString paramsArr =
546 wxSplit( imageUrl.AfterFirst( ':' ).BeforeFirst( ',' ), ';', '\0' );
547
548 data = imageUrl.AfterFirst( ',' );
549
550 if( paramsArr.size() > 0 )
551 {
552 mimeType = paramsArr[0];
553 }
554 }
555 }
556 else if( line.at( 3 ).is_string() )
557 {
558 mimeType = line.at( 3 ).get<wxString>().BeforeFirst( ';' );
559
560 start = VECTOR2D( line.at( 4 ), line.at( 5 ) );
561 size = VECTOR2D( line.at( 6 ), line.at( 7 ) );
562 //angle = line.at( 8 );
563 data = line.at( 9 ).get<wxString>();
564 }
565
566 if( mimeType.empty() || data.empty() )
567 continue;
568
569 wxMemoryBuffer buf = wxBase64Decode( data );
570
571 if( mimeType == wxS( "image/svg+xml" ) )
572 {
573 VECTOR2D offset = ScalePosSym( start );
574
575 SVG_IMPORT_PLUGIN svgImportPlugin;
576 GRAPHICS_IMPORTER_LIB_SYMBOL libsymImporter( ksymbol, 0 );
577
578 svgImportPlugin.SetImporter( &libsymImporter );
579 svgImportPlugin.LoadFromMemory( buf );
580
581 VECTOR2D imSize( svgImportPlugin.GetImageWidth(),
582 svgImportPlugin.GetImageHeight() );
583
584 VECTOR2D pixelScale( schIUScale.IUTomm( ScaleSize( size.x ) ) / imSize.x,
585 schIUScale.IUTomm( ScaleSize( size.y ) ) / imSize.y );
586
587 if( upsideDown )
588 pixelScale.y *= -1;
589
590 libsymImporter.SetScale( pixelScale );
591
592 VECTOR2D offsetMM( schIUScale.IUTomm( offset.x ), schIUScale.IUTomm( offset.y ) );
593
594 libsymImporter.SetImportOffsetMM( offsetMM );
595
596 svgImportPlugin.Import();
597
598 // TODO: rotation
599 for( std::unique_ptr<EDA_ITEM>& item : libsymImporter.GetItems() )
600 ksymbol->AddDrawItem( static_cast<SCH_ITEM*>( item.release() ) );
601 }
602 else
603 {
604 wxMemoryInputStream memis( buf.GetData(), buf.GetDataLen() );
605
606 wxImage::SetDefaultLoadFlags( wxImage::GetDefaultLoadFlags()
607 & ~wxImage::Load_Verbose );
608 wxImage img;
609 if( img.LoadFile( memis, mimeType ) )
610 {
611 int dimMul = img.GetWidth() * img.GetHeight();
612 double maxPixels = 30000;
613
614 if( dimMul > maxPixels )
615 {
616 double scale = sqrt( maxPixels / dimMul );
617 img.Rescale( img.GetWidth() * scale, img.GetHeight() * scale );
618 }
619
620 VECTOR2D pixelScale( ScaleSize( size.x ) / img.GetWidth(),
621 ScaleSize( size.y ) / img.GetHeight() );
622
623 // TODO: rotation
624 ConvertImageToLibShapes( ksymbol, 0, img, pixelScale, ScalePosSym( start ) );
625 }
626 }
627 }
628 else if( type == wxS( "HEAD" ) )
629 {
630 symInfo.head = line;
631 }
632 else if( type == wxS( "PIN" ) )
633 {
634 wxString pinId = line.at( 1 );
635 unitParentedLines[currentUnit][pinId].push_back( line );
636 }
637 else if( type == wxS( "ATTR" ) )
638 {
639 wxString parentId = line.at( 2 );
640
641 if( parentId.empty() )
642 {
643 EASYEDAPRO::SCH_ATTR attr = line;
644 unitAttributes[currentUnit].emplace( attr.key, attr );
645 }
646 else
647 {
648 unitParentedLines[currentUnit][parentId].push_back( line );
649 }
650 }
651 }
652
655 {
656 ksymbol->SetPower();
657 ksymbol->GetReferenceField().SetText( wxS( "#PWR" ) );
658 ksymbol->GetReferenceField().SetVisible( false );
659 ksymbol->SetKeyWords( wxS( "power-flag" ) );
660 ksymbol->SetShowPinNames( false );
661 ksymbol->SetShowPinNumbers( false );
662
663 if( auto globalNetAttr = get_opt( unitAttributes[1], wxS( "Global Net Name" ) ) )
664 {
665 ApplyAttrToField( fontStyles, &ksymbol->GetValueField(), *globalNetAttr, true, true );
666
667 wxString globalNetname = globalNetAttr->value;
668
669 if( !globalNetname.empty() )
670 {
671 ksymbol->SetDescription( wxString::Format(
672 _( "Power symbol creates a global label with name '%s'" ),
673 globalNetname ) );
674 }
675 }
676 }
677 else
678 {
679 auto designatorAttr = get_opt( unitAttributes[1], wxS( "Designator" ) );
680
681 if( designatorAttr && !designatorAttr->value.empty() )
682 {
683 wxString symbolPrefix = designatorAttr->value;
684
685 if( symbolPrefix.EndsWith( wxS( "?" ) ) )
686 symbolPrefix.RemoveLast();
687
688 ksymbol->GetReferenceField().SetText( symbolPrefix );
689 }
690
691 for( const wxString& attrName : c_attributesWhitelist )
692 {
693 if( auto valOpt = get_opt( aDeviceAttributes, attrName ) )
694 {
695 if( valOpt->empty() )
696 continue;
697
698 SCH_FIELD* fd = ksymbol->FindField( attrName, true );
699
700 if( !fd )
701 {
702 fd = new SCH_FIELD( ksymbol, ksymbol->GetNextAvailableFieldId(), attrName );
703 ksymbol->AddField( fd );
704 }
705
706 wxString value = *valOpt;
707
708 value.Replace( wxS( "\u2103" ), wxS( "\u00B0C" ), true ); // ℃ -> °C
709
710 fd->SetText( value );
711 fd->SetVisible( false );
712 }
713 }
714 }
715
716 for( auto& [unitId, parentedLines] : unitParentedLines )
717 {
718 for( auto& [pinId, lines] : parentedLines )
719 {
720 std::optional<EASYEDAPRO::SYM_PIN> epin;
721 std::map<wxString, EASYEDAPRO::SCH_ATTR> pinAttributes;
722
723 for( const nlohmann::json& line : lines )
724 {
725 wxString type = line.at( 0 );
726
727 if( type == wxS( "ATTR" ) )
728 {
729 EASYEDAPRO::SCH_ATTR attr = line;
730 pinAttributes.emplace( attr.key, attr );
731 }
732 else if( type == wxS( "PIN" ) )
733 {
734 epin = line;
735 }
736 }
737
738 if( !epin )
739 continue;
740
741 EASYEDAPRO::PIN_INFO pinInfo;
742 pinInfo.pin = *epin;
743
744 std::unique_ptr<SCH_PIN> pin = std::make_unique<SCH_PIN>( ksymbol );
745
746 pin->SetUnit( unitId );
747
748 pin->SetLength( ScaleSize( epin->length ) );
749 pin->SetPosition( ScalePosSym( epin->position ) );
750
751 PIN_ORIENTATION orient = PIN_ORIENTATION::PIN_RIGHT;
752
753 if( epin->rotation == 0 )
754 orient = PIN_ORIENTATION::PIN_RIGHT;
755 if( epin->rotation == 90 )
756 orient = PIN_ORIENTATION::PIN_UP;
757 if( epin->rotation == 180 )
758 orient = PIN_ORIENTATION::PIN_LEFT;
759 if( epin->rotation == 270 )
760 orient = PIN_ORIENTATION::PIN_DOWN;
761
762 pin->SetOrientation( orient );
763
765 {
766 pin->SetName( ksymbol->GetName() );
767 //pin->SetVisible( false );
768 }
769 else if( auto pinNameAttr = get_opt( pinAttributes, "NAME" ) )
770 {
771 pin->SetName( pinNameAttr->value );
772 pinInfo.name = pinNameAttr->value;
773
774 if( !pinNameAttr->valVisible )
775 pin->SetNameTextSize( schIUScale.MilsToIU( 1 ) );
776 }
777
778 if( auto pinNumAttr = get_opt( pinAttributes, "NUMBER" ) )
779 {
780 pin->SetNumber( pinNumAttr->value );
781 pinInfo.number = pinNumAttr->value;
782
783 if( !pinNumAttr->valVisible )
784 pin->SetNumberTextSize( schIUScale.MilsToIU( 1 ) );
785 }
786
788 {
789 pin->SetType( ELECTRICAL_PINTYPE::PT_POWER_IN );
790 }
791 else if( auto pinTypeAttr = get_opt( pinAttributes, "Pin Type" ) )
792 {
793 if( pinTypeAttr->value == wxS( "IN" ) )
794 pin->SetType( ELECTRICAL_PINTYPE::PT_INPUT );
795 if( pinTypeAttr->value == wxS( "OUT" ) )
796 pin->SetType( ELECTRICAL_PINTYPE::PT_OUTPUT );
797 if( pinTypeAttr->value == wxS( "BI" ) )
798 pin->SetType( ELECTRICAL_PINTYPE::PT_BIDI );
799 }
800
801 if( get_opt( pinAttributes, "NO_CONNECT" ) )
802 pin->SetType( ELECTRICAL_PINTYPE::PT_NC );
803
804 if( pin->GetNumberTextSize() * int( pin->GetNumber().size() ) > pin->GetLength() )
805 pin->SetNumberTextSize( pin->GetLength() / pin->GetNumber().size() );
806
807 symInfo.pins.push_back( pinInfo );
808 ksymbol->AddDrawItem( pin.release() );
809 }
810 }
811
812 symInfo.symbolAttr = get_opt( unitAttributes[1], "Symbol" ); // TODO: per-unit
813
814 /*BOX2I bbox = ksymbol->GetBodyBoundingBox( 0, 0, true, true );
815 bbox.Inflate( schIUScale.MilsToIU( 10 ) );*/
816
817 /*ksymbol->GetReferenceField().SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM );
818 ksymbol->GetReferenceField().SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
819 ksymbol->GetReferenceField().SetPosition( VECTOR2I( bbox.GetCenter().x, -bbox.GetTop() ) );
820
821 ksymbol->GetValueField().SetVertJustify( GR_TEXT_V_ALIGN_TOP );
822 ksymbol->GetValueField().SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
823 ksymbol->GetValueField().SetPosition( VECTOR2I( bbox.GetCenter().x, -bbox.GetBottom() ) );*/
824
825 symInfo.libSymbol = std::move( ksymbolPtr );
826
827 return symInfo;
828}
829
830
832 const nlohmann::json& aProject,
833 std::map<wxString, EASYEDAPRO::SYM_INFO>& aSymbolMap,
834 const std::map<wxString, EASYEDAPRO::BLOB>& aBlobMap,
835 const std::vector<nlohmann::json>& aLines,
836 const wxString& aLibName )
837{
838 std::vector<std::unique_ptr<SCH_ITEM>> createdItems;
839
840 std::map<wxString, std::vector<nlohmann::json>> parentedLines;
841 std::map<wxString, std::vector<nlohmann::json>> ruleLines;
842
843 std::map<wxString, nlohmann::json> lineStyles;
844 std::map<wxString, nlohmann::json> fontStyles;
845
846 for( const nlohmann::json& line : aLines )
847 {
848 wxString type = line.at( 0 );
849
850 if( type == wxS( "LINESTYLE" ) )
851 lineStyles[line.at( 1 )] = line;
852 else if( type == wxS( "FONTSTYLE" ) )
853 fontStyles[line.at( 1 )] = line;
854 }
855
856 for( const nlohmann::json& line : aLines )
857 {
858 wxString type = line.at( 0 );
859
860 if( type == wxS( "RECT" ) )
861 {
862 VECTOR2D start( line.at( 2 ), line.at( 3 ) );
863 VECTOR2D end( line.at( 4 ), line.at( 5 ) );
864 wxString styleStr = line.at( 9 );
865
866 std::unique_ptr<SCH_SHAPE> rect = std::make_unique<SCH_SHAPE>( SHAPE_T::RECTANGLE );
867
868 rect->SetStart( ScalePos( start ) );
869 rect->SetEnd( ScalePos( end ) );
870
871 ApplyLineStyle( lineStyles, rect, styleStr );
872
873 createdItems.push_back( std::move( rect ) );
874 }
875 else if( type == wxS( "CIRCLE" ) )
876 {
877 VECTOR2D center( line.at( 2 ), line.at( 3 ) );
878 double radius = line.at( 4 );
879 wxString styleStr = line.at( 5 );
880
881 std::unique_ptr<SCH_SHAPE> circle = std::make_unique<SCH_SHAPE>( SHAPE_T::CIRCLE );
882
883 circle->SetCenter( ScalePos( center ) );
884 circle->SetEnd( circle->GetCenter() + VECTOR2I( ScaleSize( radius ), 0 ) );
885
886 ApplyLineStyle( lineStyles, circle, styleStr );
887
888 createdItems.push_back( std::move( circle ) );
889 }
890 else if( type == wxS( "POLY" ) )
891 {
892 std::vector<double> points = line.at( 2 );
893 wxString styleStr = line.at( 4 );
894
895 SHAPE_LINE_CHAIN chain;
896
897 for( size_t i = 1; i < points.size(); i += 2 )
898 chain.Append( ScalePos( VECTOR2D( points[i - 1], points[i] ) ) );
899
900 for( int segId = 0; segId < chain.SegmentCount(); segId++ )
901 {
902 const SEG& seg = chain.CSegment( segId );
903
904 std::unique_ptr<SCH_LINE> schLine =
905 std::make_unique<SCH_LINE>( seg.A, LAYER_NOTES );
906 schLine->SetEndPoint( seg.B );
907
908 ApplyLineStyle( lineStyles, schLine, styleStr );
909
910 createdItems.push_back( std::move( schLine ) );
911 }
912 }
913 else if( type == wxS( "TEXT" ) )
914 {
915 VECTOR2D pos( line.at( 2 ), line.at( 3 ) );
916 double angle = line.at( 4 );
917 wxString textStr = line.at( 5 );
918 wxString fontStyleStr = line.at( 6 );
919
920 std::unique_ptr<SCH_TEXT> text =
921 std::make_unique<SCH_TEXT>( ScalePos( pos ), UnescapeHTML( textStr ) );
922
923 text->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
924 text->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
925
926 text->SetTextAngleDegrees( angle );
927
928 ApplyFontStyle( fontStyles, text, fontStyleStr );
929
930 createdItems.push_back( std::move( text ) );
931 }
932 else if( type == wxS( "OBJ" ) )
933 {
934 VECTOR2D start, size;
935 wxString mimeType, base64Data;
936 double angle = 0;
937 int flipped = 0;
938
939 if( line.at( 3 ).is_number() )
940 {
941 start = VECTOR2D( line.at( 3 ), line.at( 4 ) );
942 size = VECTOR2D( line.at( 5 ), line.at( 6 ) );
943 angle = line.at( 7 );
944 flipped = line.at( 8 );
945
946 wxString imageUrl = line.at( 9 );
947
948 if( imageUrl.BeforeFirst( ':' ) == wxS( "data" ) )
949 {
950 wxArrayString paramsArr =
951 wxSplit( imageUrl.AfterFirst( ':' ).BeforeFirst( ',' ), ';', '\0' );
952
953 base64Data = imageUrl.AfterFirst( ',' );
954
955 if( paramsArr.size() > 0 )
956 mimeType = paramsArr[0];
957 }
958 else if( imageUrl.BeforeFirst( ':' ) == wxS( "blob" ) )
959 {
960 wxString objectId = imageUrl.AfterLast( ':' );
961
962 if( auto blob = get_opt( aBlobMap, objectId ) )
963 {
964 wxString blobUrl = blob->url;
965
966 if( blobUrl.BeforeFirst( ':' ) == wxS( "data" ) )
967 {
968 wxArrayString paramsArr = wxSplit(
969 blobUrl.AfterFirst( ':' ).BeforeFirst( ',' ), ';', '\0' );
970
971 base64Data = blobUrl.AfterFirst( ',' );
972
973 if( paramsArr.size() > 0 )
974 mimeType = paramsArr[0];
975 }
976 }
977 }
978 }
979 else if( line.at( 3 ).is_string() )
980 {
981 mimeType = line.at( 3 ).get<wxString>().BeforeFirst( ';' );
982
983 start = VECTOR2D( line.at( 4 ), line.at( 5 ) );
984 size = VECTOR2D( line.at( 6 ), line.at( 7 ) );
985 angle = line.at( 8 );
986 base64Data = line.at( 9 ).get<wxString>();
987 }
988
989 VECTOR2D kstart = ScalePos( start );
990 VECTOR2D ksize = ScaleSize( size );
991
992 if( mimeType.empty() || base64Data.empty() )
993 continue;
994
995 wxMemoryBuffer buf = wxBase64Decode( base64Data );
996
997 if( mimeType == wxS( "image/svg+xml" ) )
998 {
999 SVG_IMPORT_PLUGIN svgImportPlugin;
1000 GRAPHICS_IMPORTER_SCH schImporter;
1001
1002 svgImportPlugin.SetImporter( &schImporter );
1003 svgImportPlugin.LoadFromMemory( buf );
1004
1005 VECTOR2D imSize( svgImportPlugin.GetImageWidth(),
1006 svgImportPlugin.GetImageHeight() );
1007
1008 VECTOR2D pixelScale( schIUScale.IUTomm( ScaleSize( size.x ) ) / imSize.x,
1009 schIUScale.IUTomm( ScaleSize( size.y ) ) / imSize.y );
1010
1011 schImporter.SetScale( pixelScale );
1012
1013 VECTOR2D offsetMM( schIUScale.IUTomm( kstart.x ), schIUScale.IUTomm( kstart.y ) );
1014
1015 schImporter.SetImportOffsetMM( offsetMM );
1016
1017 svgImportPlugin.Import();
1018
1019 for( std::unique_ptr<EDA_ITEM>& item : schImporter.GetItems() )
1020 {
1021 SCH_ITEM* schItem = static_cast<SCH_ITEM*>( item.release() );
1022
1023 for( double i = angle; i > 0; i -= 90 )
1024 {
1025 if( schItem->Type() == SCH_LINE_T )
1026 {
1027 // Lines need special handling for some reason
1028 schItem->SetFlags( STARTPOINT );
1029 schItem->Rotate( kstart, false );
1030 schItem->ClearFlags( STARTPOINT );
1031
1032 schItem->SetFlags( ENDPOINT );
1033 schItem->Rotate( kstart, false );
1034 schItem->ClearFlags( ENDPOINT );
1035 }
1036 else
1037 {
1038 schItem->Rotate( kstart, false );
1039 }
1040 }
1041
1042 if( flipped )
1043 {
1044 // Lines need special handling for some reason
1045 if( schItem->Type() == SCH_LINE_T )
1046 schItem->SetFlags( STARTPOINT | ENDPOINT );
1047
1048 schItem->MirrorHorizontally( kstart.x );
1049
1050 if( schItem->Type() == SCH_LINE_T )
1051 schItem->ClearFlags( STARTPOINT | ENDPOINT );
1052 }
1053
1054 createdItems.emplace_back( schItem );
1055 }
1056 }
1057 else
1058 {
1059 std::unique_ptr<SCH_BITMAP> bitmap = std::make_unique<SCH_BITMAP>();
1060
1061 wxImage::SetDefaultLoadFlags( wxImage::GetDefaultLoadFlags()
1062 & ~wxImage::Load_Verbose );
1063
1064 if( bitmap->ReadImageFile( buf ) )
1065 {
1066 VECTOR2D kcenter = kstart + ksize / 2;
1067
1068 double scaleFactor = ScaleSize( size.x ) / bitmap->GetSize().x;
1069 bitmap->SetImageScale( scaleFactor );
1070 bitmap->SetPosition( kcenter );
1071
1072 for( double i = angle; i > 0; i -= 90 )
1073 bitmap->Rotate( kstart, false );
1074
1075 if( flipped )
1076 bitmap->MirrorHorizontally( kstart.x );
1077
1078 createdItems.push_back( std::move( bitmap ) );
1079 }
1080 }
1081 }
1082 if( type == wxS( "WIRE" ) )
1083 {
1084 wxString wireId = line.at( 1 );
1085 parentedLines[wireId].push_back( line );
1086 }
1087 else if( type == wxS( "COMPONENT" ) )
1088 {
1089 wxString compId = line.at( 1 );
1090 parentedLines[compId].push_back( line );
1091 }
1092 else if( type == wxS( "ATTR" ) )
1093 {
1094 wxString compId = line.at( 2 );
1095 parentedLines[compId].push_back( line );
1096 }
1097 }
1098
1099 for( auto& [parentId, lines] : parentedLines )
1100 {
1101 std::optional<EASYEDAPRO::SCH_COMPONENT> component;
1102 std::optional<EASYEDAPRO::SCH_WIRE> wire;
1103 std::map<wxString, EASYEDAPRO::SCH_ATTR> attributes;
1104
1105 for( const nlohmann::json& line : lines )
1106 {
1107 if( line.at( 0 ) == "COMPONENT" )
1108 {
1109 component = line;
1110 }
1111 else if( line.at( 0 ) == "WIRE" )
1112 {
1113 wire = line;
1114 }
1115 else if( line.at( 0 ) == "ATTR" )
1116 {
1117 EASYEDAPRO::SCH_ATTR attr = line;
1118 attributes.emplace( attr.key, attr );
1119 }
1120 }
1121
1122 if( component )
1123 {
1124 auto deviceAttr = get_opt( attributes, "Device" );
1125 auto symbolAttr = get_opt( attributes, "Symbol" );
1126
1127 if( !deviceAttr )
1128 continue;
1129
1130 std::map<wxString, wxString> compAttrs =
1131 aProject.at( "devices" ).at( deviceAttr->value ).at( "attributes" );
1132
1133 wxString symbolId;
1134
1135 if( symbolAttr && !symbolAttr->value.IsEmpty() )
1136 symbolId = symbolAttr->value;
1137 else
1138 symbolId = compAttrs.at( "Symbol" );
1139
1140 auto it = aSymbolMap.find( symbolId );
1141 if( it == aSymbolMap.end() )
1142 {
1143 wxLogError( "Symbol of '%s' with uuid '%s' not found.", component->name, symbolId );
1144 continue;
1145 }
1146
1147 EASYEDAPRO::SYM_INFO& esymInfo = it->second;
1148 LIB_SYMBOL newLibSymbol = *esymInfo.libSymbol.get();
1149
1150 wxString unitName = component->name;
1151
1152 LIB_ID libId = EASYEDAPRO::ToKiCadLibID( aLibName,
1153 newLibSymbol.GetLibId().GetLibItemName() );
1154
1155 auto schSym = std::make_unique<SCH_SYMBOL>( newLibSymbol, libId,
1156 &aSchematic->CurrentSheet(),
1157 esymInfo.partUnits[unitName] );
1158
1159 schSym->SetFootprintFieldText( newLibSymbol.GetFootprintField().GetText() );
1160
1161 for( double i = component->rotation; i > 0; i -= 90 )
1162 schSym->Rotate( VECTOR2I(), false );
1163
1164 if( component->mirror )
1165 schSym->MirrorHorizontally( 0 );
1166
1167 schSym->SetPosition( ScalePos( component->position ) );
1168
1170 {
1171 if( auto globalNetAttr = get_opt( attributes, "Global Net Name" ) )
1172 {
1173 ApplyAttrToField( fontStyles, schSym->GetField( VALUE_FIELD ), *globalNetAttr,
1174 false, true, compAttrs, schSym.get() );
1175
1176 for( SCH_PIN* pin : schSym->GetAllLibPins() )
1177 pin->SetName( globalNetAttr->value );
1178 }
1179 else
1180 {
1181 schSym->GetField( VALUE_FIELD )
1182 ->SetText( newLibSymbol.GetValueField().GetText() );
1183 }
1184
1185 schSym->SetRef( &aSchematic->CurrentSheet(), wxS( "#PWR?" ) );
1186 schSym->GetField( REFERENCE_FIELD )->SetVisible( false );
1187 }
1188 else if( esymInfo.head.symbolType == EASYEDAPRO::SYMBOL_TYPE::NETPORT )
1189 {
1190 auto nameAttr = get_opt( attributes, "Name" );
1191
1192 if( nameAttr )
1193 {
1194 std::unique_ptr<SCH_GLOBALLABEL> label = std::make_unique<SCH_GLOBALLABEL>(
1195 ScalePos( component->position ), nameAttr->value );
1196
1198
1199 if( esymInfo.symbolAttr )
1200 {
1201 wxString symStr = esymInfo.symbolAttr->value;
1202
1203 if( symStr == wxS( "Netport-IN" ) )
1204 {
1205 spin = SPIN_STYLE::LEFT;
1206 label->SetShape( LABEL_FLAG_SHAPE::L_INPUT );
1207 }
1208 if( symStr == wxS( "Netport-OUT" ) )
1209 {
1210 spin = SPIN_STYLE::RIGHT;
1211 label->SetShape( LABEL_FLAG_SHAPE::L_OUTPUT );
1212 }
1213 if( symStr == wxS( "Netport-BI" ) )
1214 {
1215 spin = SPIN_STYLE::RIGHT;
1216 label->SetShape( LABEL_FLAG_SHAPE::L_BIDI );
1217 }
1218 }
1219
1220 for( double i = component->rotation; i > 0; i -= 90 )
1221 spin = spin.RotateCCW();
1222
1223 label->SetSpinStyle( spin );
1224
1225 nlohmann::json style = fontStyles[nameAttr->fontStyle];
1226
1227 if( !style.is_null() && style.at( 5 ).is_number() )
1228 {
1229 double size = style.at( 5 ).get<double>() * 0.5;
1230 label->SetTextSize( VECTOR2I( ScaleSize( size ), ScaleSize( size ) ) );
1231 }
1232
1233 createdItems.push_back( std::move( label ) );
1234 }
1235
1236 continue;
1237 }
1238 else
1239 {
1240 for( const wxString& attrKey : c_attributesWhitelist )
1241 {
1242 if( auto valOpt = get_opt( compAttrs, attrKey ) )
1243 {
1244 if( valOpt->empty() )
1245 continue;
1246
1247 SCH_FIELD* text = schSym->FindField( attrKey, true );
1248
1249 if( !text )
1250 {
1251 text = schSym->AddField(
1252 SCH_FIELD( schSym.get(), schSym->GetFieldCount(), attrKey ) );
1253 }
1254
1255 wxString value = *valOpt;
1256
1257 value.Replace( wxS( "\u2103" ), wxS( "\u00B0C" ), true ); // ℃ -> °C
1258
1259 text->SetText( value );
1260 text->SetVisible( false );
1261 }
1262 }
1263
1264 auto nameAttr = get_opt( attributes, "Name" );
1265 auto valueAttr = get_opt( attributes, "Value" );
1266
1267 std::optional<EASYEDAPRO::SCH_ATTR> targetValueAttr;
1268
1269 if( valueAttr && !valueAttr->value.empty() && valueAttr->valVisible )
1270 targetValueAttr = valueAttr;
1271 else if( nameAttr && !nameAttr->value.empty() && nameAttr->valVisible )
1272 targetValueAttr = nameAttr;
1273 else if( valueAttr && !valueAttr->value.empty() )
1274 targetValueAttr = valueAttr;
1275 else if( nameAttr && !nameAttr->value.empty() )
1276 targetValueAttr = nameAttr;
1277
1278 if( targetValueAttr )
1279 {
1280 ApplyAttrToField( fontStyles, schSym->GetField( VALUE_FIELD ), *targetValueAttr,
1281 false, true, compAttrs, schSym.get() );
1282 }
1283
1284 if( auto descrAttr = get_opt( attributes, "Description" ) )
1285 {
1286 ApplyAttrToField( fontStyles, schSym->GetField( DESCRIPTION_FIELD ), *descrAttr,
1287 false, true, compAttrs, schSym.get() );
1288 }
1289
1290 if( auto designatorAttr = get_opt( attributes, "Designator" ) )
1291 {
1292 ApplyAttrToField( fontStyles, schSym->GetField( REFERENCE_FIELD ),
1293 *designatorAttr, false, true, compAttrs, schSym.get() );
1294
1295 schSym->SetRef( &aSchematic->CurrentSheet(), designatorAttr->value );
1296 }
1297
1298 for( auto& [attrKey, attr] : attributes )
1299 {
1300 if( attrKey == wxS( "Name" ) || attrKey == wxS( "Value" )
1301 || attrKey == wxS( "Global Net Name" ) || attrKey == wxS( "Designator" )
1302 || attrKey == wxS( "Description" ) || attrKey == wxS( "Device" )
1303 || attrKey == wxS( "Footprint" ) || attrKey == wxS( "Symbol" )
1304 || attrKey == wxS( "Unique ID" ) )
1305 {
1306 continue;
1307 }
1308
1309 if( attr.value.IsEmpty() )
1310 continue;
1311
1312 SCH_FIELD* text = schSym->FindField( attrKey, true );
1313
1314 if( !text )
1315 {
1316 text = schSym->AddField(
1317 SCH_FIELD( schSym.get(), schSym->GetFieldCount(), attrKey ) );
1318 }
1319
1320 text->SetPosition( schSym->GetPosition() );
1321
1322 ApplyAttrToField( fontStyles, text, attr, false, true, compAttrs,
1323 schSym.get() );
1324 }
1325 }
1326
1327 for( const EASYEDAPRO::PIN_INFO& pinInfo : esymInfo.pins )
1328 {
1329 wxString pinKey = parentId + pinInfo.pin.id;
1330 auto pinLines = get_opt( parentedLines, pinKey );
1331
1332 if( !pinLines )
1333 continue;
1334
1335 for( const nlohmann::json& pinLine : *pinLines )
1336 {
1337 if( pinLine.at( 0 ) != "ATTR" )
1338 continue;
1339
1340 EASYEDAPRO::SCH_ATTR attr = pinLine;
1341
1342 if( attr.key != wxS( "NO_CONNECT" ) )
1343 continue;
1344
1345 if( SCH_PIN* schPin = schSym->GetPin( pinInfo.number ) )
1346 {
1347 VECTOR2I pos = schSym->GetPinPhysicalPosition( schPin->GetLibPin() );
1348
1349 std::unique_ptr<SCH_NO_CONNECT> noConn =
1350 std::make_unique<SCH_NO_CONNECT>( pos );
1351
1352 createdItems.push_back( std::move( noConn ) );
1353 }
1354 }
1355 }
1356
1357 createdItems.push_back( std::move( schSym ) );
1358 }
1359 else // Not component
1360 {
1361 std::vector<SHAPE_LINE_CHAIN> wireLines;
1362
1363 if( wire )
1364 {
1365 for( const std::vector<double>& ptArr : wire->geometry )
1366 {
1367 SHAPE_LINE_CHAIN chain;
1368
1369 for( size_t i = 1; i < ptArr.size(); i += 2 )
1370 chain.Append( ScalePos( VECTOR2D( ptArr[i - 1], ptArr[i] ) ) );
1371
1372 if( chain.PointCount() < 2 )
1373 continue;
1374
1375 wireLines.push_back( chain );
1376
1377 for( int segId = 0; segId < chain.SegmentCount(); segId++ )
1378 {
1379 const SEG& seg = chain.CSegment( segId );
1380
1381 std::unique_ptr<SCH_LINE> schLine =
1382 std::make_unique<SCH_LINE>( seg.A, LAYER_WIRE );
1383 schLine->SetEndPoint( seg.B );
1384
1385 createdItems.push_back( std::move( schLine ) );
1386 }
1387 }
1388 }
1389
1390 auto netAttr = get_opt( attributes, "NET" );
1391
1392 if( netAttr )
1393 {
1394 if( !netAttr->valVisible )
1395 continue;
1396
1397 VECTOR2I kpos = ScalePos( *netAttr->position );
1398 VECTOR2I nearestPos = kpos;
1399 SEG::ecoord min_dist_sq = VECTOR2I::ECOORD_MAX;
1400
1401 for( const SHAPE_LINE_CHAIN& chain : wireLines )
1402 {
1403 VECTOR2I nearestPt = chain.NearestPoint( kpos, false );
1404 SEG::ecoord dist_sq = ( nearestPt - kpos ).SquaredEuclideanNorm();
1405
1406 if( dist_sq < min_dist_sq )
1407 {
1408 min_dist_sq = dist_sq;
1409 nearestPos = nearestPt;
1410 }
1411 }
1412
1413 std::unique_ptr<SCH_LABEL> label = std::make_unique<SCH_LABEL>();
1414
1415 label->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
1416 label->SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM );
1417
1418 for( double i = netAttr->rotation; i > 0; i -= 90 )
1419 label->Rotate90( true );
1420
1421 label->SetPosition( nearestPos );
1422 label->SetText( netAttr->value );
1423
1424 ApplyFontStyle( fontStyles, label, netAttr->fontStyle );
1425
1426 createdItems.push_back( std::move( label ) );
1427 }
1428 }
1429 }
1430
1431 // Adjust page to content
1432 BOX2I sheetBBox;
1433
1434 for( std::unique_ptr<SCH_ITEM>& ptr : createdItems )
1435 {
1436 if( ptr->Type() == SCH_SYMBOL_T )
1437 sheetBBox.Merge( static_cast<SCH_SYMBOL*>( ptr.get() )->GetBodyAndPinsBoundingBox() );
1438 else
1439 sheetBBox.Merge( ptr->GetBoundingBox() );
1440 }
1441
1442 SCH_SCREEN* screen = aRootSheet->GetScreen();
1443 PAGE_INFO pageInfo = screen->GetPageSettings();
1444
1445 int alignGrid = schIUScale.MilsToIU( 50 );
1446
1447 VECTOR2D offset( -sheetBBox.GetLeft(), -sheetBBox.GetTop() );
1448 offset.x = KiROUND( offset.x / alignGrid ) * alignGrid;
1449 offset.y = KiROUND( offset.y / alignGrid ) * alignGrid;
1450
1451 pageInfo.SetWidthMils( schIUScale.IUToMils( sheetBBox.GetWidth() ) );
1452 pageInfo.SetHeightMils( schIUScale.IUToMils( sheetBBox.GetHeight() ) );
1453
1454 screen->SetPageSettings( pageInfo );
1455
1456 for( std::unique_ptr<SCH_ITEM>& ptr : createdItems )
1457 {
1458 ptr->Move( offset );
1459 screen->Append( ptr.release() );
1460 }
1461}
int color
Definition: DXF_plotter.cpp:58
constexpr EDA_IU_SCALE schIUScale
Definition: base_units.h:110
size_type GetHeight() const
Definition: box2.h:205
coord_type GetTop() const
Definition: box2.h:219
size_type GetWidth() const
Definition: box2.h:204
coord_type GetLeft() const
Definition: box2.h:218
BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition: box2.h:623
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:126
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:100
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: eda_item.h:128
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:83
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:98
virtual void SetVisible(bool aVisible)
Definition: eda_text.cpp:243
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)
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:77
const LIB_ID & GetLibId() const override
Definition: lib_symbol.h:142
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:679
SCH_FIELD & GetFootprintField() const
Return reference to the footprint field.
wxString GetName() const override
Definition: lib_symbol.h:136
void SetDescription(const wxString &aDescription)
Gets the Description field text value *‍/.
Definition: lib_symbol.h:151
void SetKeyWords(const wxString &aKeyWords)
Definition: lib_symbol.h:168
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:969
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.
Holds all the data relating to one schematic.
Definition: schematic.h:75
SCH_SHEET_PATH & CurrentSheet() const override
Definition: schematic.h:136
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:1138
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:174
virtual void MirrorHorizontally(int aCenter)
Mirror item horizontally about aCenter.
Definition: sch_item.h:351
virtual void Rotate(const VECTOR2I &aCenter, bool aRotateCCW)
Rotate the item around aCenter 90 degrees in the clockwise direction.
Definition: sch_item.h:367
const PAGE_INFO & GetPageSettings() const
Definition: sch_screen.h:130
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Definition: sch_screen.cpp:152
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:105
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.
SPIN_STYLE RotateCCW()
Definition: sch_label.cpp:157
Simple container to manage line stroke parameters.
Definition: stroke_params.h:81
void SetLineStyle(LINE_STYLE aLineStyle)
Definition: stroke_params.h:95
void SetWidth(int aWidth)
Definition: stroke_params.h:92
void SetColor(const KIGFX::COLOR4D &aColor)
Definition: stroke_params.h:98
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:75
#define _(s)
static constexpr EDA_ANGLE ANGLE_VERTICAL
Definition: eda_angle.h:432
static constexpr EDA_ANGLE ANGLE_HORIZONTAL
Definition: eda_angle.h:431
#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)
PIN_ORIENTATION
The symbol library pin object orientations.
Definition: pin_type.h:77
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:84
@ SYM_MIRROR_Y
Definition: sch_symbol.h:86
@ SYM_ORIENT_180
Definition: sch_symbol.h:83
@ SYM_MIRROR_X
Definition: sch_symbol.h:85
@ SYM_ORIENT_90
Definition: sch_symbol.h:82
@ SYM_ORIENT_0
Definition: sch_symbol.h:81
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:48
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
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:118
VECTOR2< double > VECTOR2D
Definition: vector2d.h:601
VECTOR2< int > VECTOR2I
Definition: vector2d.h:602