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