KiCad PCB EDA Suite
Loading...
Searching...
No Matches
sch_easyeda_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
25#include "sch_easyeda_parser.h"
26
27#include <sch_io/sch_io_mgr.h>
28#include <schematic.h>
29#include <sch_sheet.h>
30#include <sch_line.h>
31#include <sch_no_connect.h>
32#include <sch_label.h>
33#include <sch_junction.h>
34#include <sch_edit_frame.h>
35#include <sch_shape.h>
36#include <sch_bitmap.h>
37#include <string_utils.h>
38#include <bezier_curves.h>
39#include <wx/base64.h>
40#include <wx/mstream.h>
41#include <core/map_helpers.h>
42#include <gfx_import_utils.h>
46
47
48// clang-format off
49static const std::vector<wxString> c_attributesWhitelist = { "Datasheet",
50 "Manufacturer Part",
51 "Manufacturer",
52 "BOM_Manufacturer Part",
53 "BOM_Manufacturer",
54 "Supplier Part",
55 "Supplier",
56 "BOM_Supplier Part",
57 "BOM_Supplier",
58 "LCSC Part Name" };
59// clang-format on
60
61
63 PROGRESS_REPORTER* aProgressReporter )
64{
65 m_schematic = aSchematic;
66}
67
68
70{
71}
72
73
74static std::vector<std::vector<wxString>> RegexMatchAll( wxRegEx& aRegex, const wxString& aString )
75{
76 std::vector<std::vector<wxString>> allMatches;
77
78 size_t start = 0;
79 size_t len = 0;
80 size_t prevstart = 0;
81
82 wxString str = aString;
83
84 while( aRegex.Matches( str ) )
85 {
86 std::vector<wxString> matches;
87 aRegex.GetMatch( &start, &len );
88
89 for( size_t i = 0; i < aRegex.GetMatchCount(); i++ )
90 matches.emplace_back( aRegex.GetMatch( str, i ) );
91
92 allMatches.emplace_back( matches );
93
94 prevstart = start + len;
95 str = str.Mid( prevstart );
96 }
97
98 return allMatches;
99}
100
101
109static std::vector<std::pair<wxString, std::vector<double>>>
110ParseImageTransform( const wxString& transformData )
111{
112 wxRegEx transformRegex( "(rotate|translate|scale)\\(([\\w\\s,\\.\\-]*)\\)", wxRE_ICASE );
113 std::vector<std::vector<wxString>> allMatches = RegexMatchAll( transformRegex, transformData );
114
115 std::vector<std::pair<wxString, std::vector<double>>> transformCmds;
116
117 for( int cmdId = allMatches.size() - 1; cmdId >= 0; cmdId-- )
118 {
119 std::vector<wxString>& groups = allMatches[cmdId];
120
121 if( groups.size() != 3 )
122 continue;
123
124 const wxString& cmdName = groups[1].Strip( wxString::both ).Lower();
125 const wxString& cmdArgsStr = groups[2];
126
127 wxArrayString cmdParts = wxSplit( cmdArgsStr, ',', '\0' );
128 std::vector<double> cmdArgs;
129
130 for( const wxString& cmdPart : cmdParts )
131 {
132 double arg = 0;
133 wxASSERT( cmdPart.Strip( wxString::both ).ToCDouble( &arg ) );
134
135 cmdArgs.push_back( arg );
136 }
137
138 transformCmds.emplace_back( cmdName, cmdArgs );
139 }
140
141 return transformCmds;
142}
143
144
145static LIB_ID EasyEdaToKiCadLibID( const wxString& aLibName, const wxString& aLibReference )
146{
147 wxString libReference = EscapeString( aLibReference, CTX_LIBID );
148
149 wxString key = !aLibName.empty() ? ( aLibName + ':' + libReference ) : libReference;
150
151 LIB_ID libId;
152 libId.Parse( key, true );
153
154 return libId;
155}
156
157
158static LINE_STYLE ConvertStrokeStyle( const wxString& aStyle )
159{
160 if( aStyle == wxS( "0" ) )
161 return LINE_STYLE::SOLID;
162 else if( aStyle == wxS( "1" ) )
163 return LINE_STYLE::DASH;
164 else if( aStyle == wxS( "2" ) )
165 return LINE_STYLE::DOT;
166
167 return LINE_STYLE::DEFAULT;
168}
169
170
171static ELECTRICAL_PINTYPE ConvertElecType( const wxString& aType )
172{
173 if( aType == wxS( "0" ) )
175 else if( aType == wxS( "1" ) )
177 else if( aType == wxS( "2" ) )
179 else if( aType == wxS( "3" ) )
181 else if( aType == wxS( "4" ) )
183
185}
186
187
189 REPORTER* aReporter )
190{
192 {
195 line1->AddPoint( { 0, 0 } );
196 line1->AddPoint( { 0, schIUScale.MilsToIU( -50 ) } );
197 aKsymbol->AddDrawItem( line1, false );
198
200 {
203 circle->SetPosition( { schIUScale.MilsToIU( 0 ), schIUScale.MilsToIU( -75 ) } );
204 circle->SetEnd( circle->GetPosition() + VECTOR2I( schIUScale.MilsToIU( 25 ), 0 ) );
205 aKsymbol->AddDrawItem( circle, false );
206 }
207 else
208 {
211 line2->AddPoint( { schIUScale.MilsToIU( -25 ), schIUScale.MilsToIU( -50 ) } );
212 line2->AddPoint( { schIUScale.MilsToIU( 25 ), schIUScale.MilsToIU( -50 ) } );
213 line2->AddPoint( { schIUScale.MilsToIU( 0 ), schIUScale.MilsToIU( -100 ) } );
214 line2->AddPoint( { schIUScale.MilsToIU( -25 ), schIUScale.MilsToIU( -50 ) } );
215 aKsymbol->AddDrawItem( line2, false );
216 }
217
218 return { 0, schIUScale.MilsToIU( 150 ) };
219 }
220 else if( aStyle == EASYEDA::POWER_FLAG_STYLE::WAVE )
221 {
224 line->AddPoint( { 0, 0 } );
225 line->AddPoint( { 0, schIUScale.MilsToIU( -72 ) } );
226 aKsymbol->AddDrawItem( line, false );
227
230 bezier->AddPoint( { schIUScale.MilsToIU( 30 ), schIUScale.MilsToIU( -50 ) } );
231 bezier->AddPoint( { schIUScale.MilsToIU( 30 ), schIUScale.MilsToIU( -87 ) } );
232 bezier->AddPoint( { schIUScale.MilsToIU( -30 ), schIUScale.MilsToIU( -63 ) } );
233 bezier->AddPoint( { schIUScale.MilsToIU( -30 ), schIUScale.MilsToIU( -100 ) } );
234 aKsymbol->AddDrawItem( bezier, false );
235
236 return { 0, schIUScale.MilsToIU( 150 ) };
237 }
242 {
245 line1->AddPoint( { 0, 0 } );
246 line1->AddPoint( { 0, schIUScale.MilsToIU( -100 ) } );
247 aKsymbol->AddDrawItem( line1, false );
248
250 {
253 line2->AddPoint( { schIUScale.MilsToIU( -100 ), schIUScale.MilsToIU( -100 ) } );
254 line2->AddPoint( { schIUScale.MilsToIU( 100 ), schIUScale.MilsToIU( -100 ) } );
255 aKsymbol->AddDrawItem( line2, false );
256
259 line3->AddPoint( { schIUScale.MilsToIU( -70 ), schIUScale.MilsToIU( -120 ) } );
260 line3->AddPoint( { schIUScale.MilsToIU( 70 ), schIUScale.MilsToIU( -120 ) } );
261 aKsymbol->AddDrawItem( line3, false );
262
265 line4->AddPoint( { schIUScale.MilsToIU( -40 ), schIUScale.MilsToIU( -140 ) } );
266 line4->AddPoint( { schIUScale.MilsToIU( 40 ), schIUScale.MilsToIU( -140 ) } );
267 aKsymbol->AddDrawItem( line4, false );
268
271 line5->AddPoint( { schIUScale.MilsToIU( -10 ), schIUScale.MilsToIU( -160 ) } );
272 line5->AddPoint( { schIUScale.MilsToIU( 10 ), schIUScale.MilsToIU( -160 ) } );
273 aKsymbol->AddDrawItem( line5, false );
274 }
276 {
279 line2->AddPoint( { schIUScale.MilsToIU( -100 ), schIUScale.MilsToIU( -100 ) } );
280 line2->AddPoint( { schIUScale.MilsToIU( 100 ), schIUScale.MilsToIU( -100 ) } );
281 line2->AddPoint( { schIUScale.MilsToIU( 0 ), schIUScale.MilsToIU( -160 ) } );
282 line2->AddPoint( { schIUScale.MilsToIU( -100 ), schIUScale.MilsToIU( -100 ) } );
283 aKsymbol->AddDrawItem( line2, false );
284 }
285 else if( aStyle == EASYEDA::POWER_FLAG_STYLE::EARTH )
286 {
289 line2->AddPoint( { schIUScale.MilsToIU( -150 ), schIUScale.MilsToIU( -200 ) } );
290 line2->AddPoint( { schIUScale.MilsToIU( -100 ), schIUScale.MilsToIU( -100 ) } );
291 line2->AddPoint( { schIUScale.MilsToIU( 100 ), schIUScale.MilsToIU( -100 ) } );
292 line2->AddPoint( { schIUScale.MilsToIU( 50 ), schIUScale.MilsToIU( -200 ) } );
293 aKsymbol->AddDrawItem( line2, false );
294
297 line3->AddPoint( { schIUScale.MilsToIU( 0 ), schIUScale.MilsToIU( -100 ) } );
298 line3->AddPoint( { schIUScale.MilsToIU( -50 ), schIUScale.MilsToIU( -200 ) } );
299 aKsymbol->AddDrawItem( line3, false );
300 }
301 else // EASYEDA::POWER_FLAG_STYLE::GOST_ARROW
302 {
305 line2->AddPoint( { schIUScale.MilsToIU( -25 ), schIUScale.MilsToIU( -50 ) } );
306 line2->AddPoint( { schIUScale.MilsToIU( 0 ), schIUScale.MilsToIU( -100 ) } );
307 line2->AddPoint( { schIUScale.MilsToIU( 25 ), schIUScale.MilsToIU( -50 ) } );
308 aKsymbol->AddDrawItem( line2, false );
309
310 return { 0, schIUScale.MilsToIU( 150 ) }; // special case
311 }
312
313 return { 0, schIUScale.MilsToIU( 250 ) };
314 }
317 {
320 line1->AddPoint( { 0, 0 } );
321 line1->AddPoint( { 0, schIUScale.MilsToIU( -160 ) } );
322 aKsymbol->AddDrawItem( line1, false );
323
326 line2->AddPoint( { schIUScale.MilsToIU( -100 ), schIUScale.MilsToIU( -160 ) } );
327 line2->AddPoint( { schIUScale.MilsToIU( 100 ), schIUScale.MilsToIU( -160 ) } );
328 aKsymbol->AddDrawItem( line2, false );
329
332 line3->AddPoint( { schIUScale.MilsToIU( -60 ), schIUScale.MilsToIU( -200 ) } );
333 line3->AddPoint( { schIUScale.MilsToIU( 60 ), schIUScale.MilsToIU( -200 ) } );
334 aKsymbol->AddDrawItem( line3, false );
335
338 line4->AddPoint( { schIUScale.MilsToIU( -20 ), schIUScale.MilsToIU( -240 ) } );
339 line4->AddPoint( { schIUScale.MilsToIU( 20 ), schIUScale.MilsToIU( -240 ) } );
340 aKsymbol->AddDrawItem( line4, false );
341
343 return { 0, schIUScale.MilsToIU( 300 ) };
344
347 circle->SetPosition( { schIUScale.MilsToIU( 0 ), schIUScale.MilsToIU( -160 ) } );
348 circle->SetEnd( circle->GetPosition() + VECTOR2I( schIUScale.MilsToIU( 120 ), 0 ) );
349 aKsymbol->AddDrawItem( circle, false );
350
351 return { 0, schIUScale.MilsToIU( 350 ) };
352 }
353 else if( aStyle == EASYEDA::POWER_FLAG_STYLE::GOST_BAR )
354 {
357 line1->AddPoint( { 0, 0 } );
358 line1->AddPoint( { 0, schIUScale.MilsToIU( -200 ) } );
359 aKsymbol->AddDrawItem( line1, false );
360
363 line2->AddPoint( { schIUScale.MilsToIU( -100 ), schIUScale.MilsToIU( -200 ) } );
364 line2->AddPoint( { schIUScale.MilsToIU( 100 ), schIUScale.MilsToIU( -200 ) } );
365 aKsymbol->AddDrawItem( line2, false );
366
367 return { 0, schIUScale.MilsToIU( 250 ) };
368 }
369 else
370 {
371 if( aStyle != EASYEDA::POWER_FLAG_STYLE::BAR )
372 {
373 aReporter->Report( _( "Power Port with unknown style imported as 'Bar' type." ),
375 }
376
379 line1->AddPoint( { 0, 0 } );
380 line1->AddPoint( { 0, schIUScale.MilsToIU( -100 ) } );
381 aKsymbol->AddDrawItem( line1, false );
382
385 line2->AddPoint( { schIUScale.MilsToIU( -50 ), schIUScale.MilsToIU( -100 ) } );
386 line2->AddPoint( { schIUScale.MilsToIU( 50 ), schIUScale.MilsToIU( -100 ) } );
387 aKsymbol->AddDrawItem( line2, false );
388
389 return { 0, schIUScale.MilsToIU( 150 ) };
390 }
391}
392
393
395 std::map<wxString, wxString> paramMap,
396 wxArrayString aShapes )
397{
398 for( wxString shapeStr : aShapes )
399 {
400 wxArrayString arr = wxSplit( shapeStr, '~', '\0' );
401
402 wxString elType = arr[0];
403 if( elType == wxS( "PL" ) || elType == wxS( "PG" ) )
404 {
405 wxArrayString ptArr = wxSplit( arr[1], ' ', '\0' );
406 wxString strokeColor = arr[2];
407 double lineWidth = Convert( arr[3] );
408 LINE_STYLE strokeStyle = ConvertStrokeStyle( arr[4] );
409 wxString fillColor = arr[5].Lower();
410 //bool locked = arr[7] != wxS( "0" );
411
412 SHAPE_LINE_CHAIN chain;
413
414 for( size_t i = 1; i < ptArr.size(); i += 2 )
415 {
416 chain.Append(
417 RelPosSym( VECTOR2I( Convert( ptArr[i - 1] ), Convert( ptArr[i] ) ) ) );
418 }
419
420 auto line = std::make_unique<SCH_SHAPE>( SHAPE_T::POLY, LAYER_DEVICE );
421
422 if( elType == wxS( "PG" ) )
423 chain.SetClosed( true );
424
425 if( chain.PointCount() < 2 )
426 continue;
427
428 for( int i = 0; i < chain.PointCount(); i++ )
429 line->AddPoint( chain.CPoint( i ) );
430
431 if( chain.IsClosed() )
432 line->AddPoint( chain.CPoint( 0 ) );
433
434 line->SetUnit( 0 );
435 line->SetStroke( STROKE_PARAMS( ScaleSize( lineWidth ), strokeStyle ) );
436
437 if( fillColor != wxS( "none" ) )
438 {
439 line->SetFilled( true );
440
441 if( fillColor == strokeColor )
442 line->SetFillMode( FILL_T::FILLED_SHAPE );
443 else
444 line->SetFillMode( FILL_T::FILLED_WITH_BG_BODYCOLOR );
445 }
446
447 aSymbol->AddDrawItem( line.release() );
448 }
449 else if( elType == wxS( "PT" ) ) // Freedraw
450 {
451 wxString pointsData = arr[1];
452 wxString strokeColor = arr[2];
453 double lineWidth = Convert( arr[3] );
454 LINE_STYLE strokeStyle = ConvertStrokeStyle( arr[4] );
455 wxString fillColor = arr[5].Lower();
456 //bool locked = arr[7] != wxS( "0" );
457
458 std::vector<SHAPE_LINE_CHAIN> lineChains =
459 ParseLineChains( pointsData, schIUScale.MilsToIU( 10 ), false );
460
461 for( SHAPE_LINE_CHAIN outline : lineChains )
462 {
463 auto shape = std::make_unique<SCH_SHAPE>( SHAPE_T::POLY, LAYER_DEVICE );
464
465 if( outline.IsClosed() )
466 outline.Append( outline.CPoint( 0 ), true );
467
468 for( const VECTOR2I& pt : outline.CPoints() )
469 shape->AddPoint( pt );
470
471 shape->SetUnit( 0 );
472 shape->SetStroke( STROKE_PARAMS( ScaleSize( lineWidth ), strokeStyle ) );
473
474 if( fillColor != wxS( "none" ) )
475 {
476 shape->SetFilled( true );
477
478 if( fillColor == strokeColor )
479 shape->SetFillMode( FILL_T::FILLED_SHAPE );
480 else
481 shape->SetFillMode( FILL_T::FILLED_WITH_BG_BODYCOLOR );
482 }
483
484 aSymbol->AddDrawItem( shape.release() );
485 }
486 }
487 else if( elType == wxS( "Pimage" ) )
488 {
489 //double angle = Convert( arr[4] ); // TODO
490 VECTOR2D start( Convert( arr[6] ), Convert( arr[7] ) );
491 VECTOR2D size( Convert( arr[8] ), Convert( arr[9] ) );
492 wxString imageUrl = arr[10];
493
494 if( imageUrl.BeforeFirst( ':' ) == wxS( "data" ) )
495 {
496 wxArrayString paramsArr =
497 wxSplit( imageUrl.AfterFirst( ':' ).BeforeFirst( ',' ), ';', '\0' );
498
499 wxString data = imageUrl.AfterFirst( ',' );
500
501 if( paramsArr.size() > 0 )
502 {
503 wxString mimeType = paramsArr[0];
504 wxMemoryBuffer buf = wxBase64Decode( data );
505
506 if( mimeType == wxS( "image/svg+xml" ) )
507 {
508 VECTOR2D offset = RelPosSym( start );
509
510 SVG_IMPORT_PLUGIN svgImportPlugin;
511 GRAPHICS_IMPORTER_LIB_SYMBOL libsymImporter( aSymbol, 0 );
512
513 svgImportPlugin.SetImporter( &libsymImporter );
514 svgImportPlugin.LoadFromMemory( buf );
515
516 VECTOR2D imSize( svgImportPlugin.GetImageWidth(),
517 svgImportPlugin.GetImageHeight() );
518
519 VECTOR2D pixelScale( schIUScale.IUTomm( ScaleSize( size.x ) ) / imSize.x,
520 schIUScale.IUTomm( ScaleSize( size.y ) ) / imSize.y );
521
522 libsymImporter.SetScale( pixelScale );
523
524 VECTOR2D offsetMM( schIUScale.IUTomm( offset.x ),
525 schIUScale.IUTomm( offset.y ) );
526
527 libsymImporter.SetImportOffsetMM( offsetMM );
528
529 svgImportPlugin.Import();
530
531 for( std::unique_ptr<EDA_ITEM>& item : libsymImporter.GetItems() )
532 aSymbol->AddDrawItem( static_cast<SCH_ITEM*>( item.release() ) );
533 }
534 else
535 {
536 wxMemoryInputStream memis( buf.GetData(), buf.GetDataLen() );
537
538 wxImage::SetDefaultLoadFlags( wxImage::GetDefaultLoadFlags()
539 & ~wxImage::Load_Verbose );
540 wxImage img;
541 if( img.LoadFile( memis, mimeType ) )
542 {
543 int dimMul = img.GetWidth() * img.GetHeight();
544 double maxPixels = 30000;
545
546 if( dimMul > maxPixels )
547 {
548 double scale = sqrt( maxPixels / dimMul );
549 img.Rescale( img.GetWidth() * scale, img.GetHeight() * scale );
550 }
551
552 VECTOR2D pixelScale( ScaleSize( size.x ) / img.GetWidth(),
553 ScaleSize( size.y ) / img.GetHeight() );
554
555 ConvertImageToLibShapes( aSymbol, 0, img, pixelScale,
556 RelPosSym( start ) );
557 }
558 }
559 }
560 }
561 }
562 else if( elType == wxS( "A" ) )
563 {
564 wxString data = arr[1];
565 wxString strokeColor = arr[3];
566 double lineWidth = Convert( arr[4] );
567 LINE_STYLE strokeStyle = ConvertStrokeStyle( arr[5] );
568 wxString fillColor = arr[6].Lower();
569 //bool locked = arr[8] != wxS( "0" );
570
571 std::vector<SHAPE_LINE_CHAIN> chains =
572 ParseLineChains( data, schIUScale.MilsToIU( 10 ), false );
573
574 auto transform = []( VECTOR2I aVec )
575 {
576 return VECTOR2I( aVec.x, aVec.y );
577 };
578
579 for( const SHAPE_LINE_CHAIN& chain : chains )
580 {
581 for( int i = 0; i <= chain.PointCount() && i != -1; i = chain.NextShape( i ) )
582 {
583 if( chain.IsArcStart( i ) )
584 {
585 SHAPE_ARC arc = chain.Arc( chain.ArcIndex( i ) );
586
587 std::unique_ptr<SCH_SHAPE> shape =
588 std::make_unique<SCH_SHAPE>( SHAPE_T::ARC, LAYER_DEVICE );
589
590 shape->SetArcGeometry( transform( arc.GetP0() ),
591 transform( arc.GetArcMid() ),
592 transform( arc.GetP1() ) );
593
594 shape->SetUnit( 0 );
595 shape->SetStroke( STROKE_PARAMS( ScaleSize( lineWidth ), strokeStyle ) );
596
597 if( fillColor != wxS( "none" ) )
598 {
599 shape->SetFilled( true );
600
601 if( fillColor == strokeColor )
602 shape->SetFillMode( FILL_T::FILLED_SHAPE );
603 else
604 shape->SetFillMode( FILL_T::FILLED_WITH_BG_BODYCOLOR );
605 }
606
607 aSymbol->AddDrawItem( shape.release() );
608 }
609 else
610 {
611 SEG seg = chain.CSegment( i );
612
613 std::unique_ptr<SCH_SHAPE> shape =
614 std::make_unique<SCH_SHAPE>( SHAPE_T::POLY, LAYER_DEVICE );
615
616 shape->AddPoint( transform( seg.A ) );
617 shape->AddPoint( transform( seg.B ) );
618
619 shape->SetUnit( 0 );
620 shape->SetStroke( STROKE_PARAMS( ScaleSize( lineWidth ), strokeStyle ) );
621
622 aSymbol->AddDrawItem( shape.release() );
623 }
624 }
625 }
626 }
627 else if( elType == wxS( "R" ) )
628 {
629 VECTOR2D start( Convert( arr[1] ), Convert( arr[2] ) );
630
631 VECTOR2D cr;
632 cr.x = !arr[3].empty() ? Convert( arr[3] ) : 0,
633 cr.y = !arr[4].empty() ? Convert( arr[4] ) : 0; // TODO: corner radius
634
635 VECTOR2D size( Convert( arr[5] ), Convert( arr[6] ) );
636 wxString strokeColor = arr[7];
637 double lineWidth = Convert( arr[8] );
638 LINE_STYLE strokeStyle = ConvertStrokeStyle( arr[9] );
639 wxString fillColor = arr[10].Lower();
640 //bool locked = arr[12] != wxS( "0" );
641
642 //if( cr.x == 0 )
643 {
644 auto rect = std::make_unique<SCH_SHAPE>( SHAPE_T::RECTANGLE, LAYER_DEVICE );
645
646 rect->SetStart( RelPosSym( start ) );
647 rect->SetEnd( RelPosSym( start + size ) );
648
649 rect->SetUnit( 0 );
650 rect->SetStroke( STROKE_PARAMS( ScaleSize( lineWidth ), strokeStyle ) );
651
652 if( fillColor != wxS( "none" ) )
653 {
654 rect->SetFilled( true );
655
656 if( fillColor == strokeColor )
657 rect->SetFillMode( FILL_T::FILLED_SHAPE );
658 else
659 rect->SetFillMode( FILL_T::FILLED_WITH_BG_BODYCOLOR );
660 }
661
662 aSymbol->AddDrawItem( rect.release() );
663 }
664 // TODO: rounded rectangles
665 }
666 else if( elType == wxS( "E" ) )
667 {
668 auto circle = std::make_unique<SCH_SHAPE>( SHAPE_T::CIRCLE, LAYER_DEVICE );
669
670 VECTOR2D center( Convert( arr[1] ), Convert( arr[2] ) );
671 VECTOR2D radius( Convert( arr[3] ), Convert( arr[4] ) ); // TODO: corner radius
672 wxString strokeColor = arr[5];
673 double lineWidth = Convert( arr[6] );
674 LINE_STYLE strokeStyle = ConvertStrokeStyle( arr[7] );
675 wxString fillColor = arr[8].Lower();
676 //bool locked = arr[10] != wxS( "0" );
677
678 circle->SetCenter( RelPosSym( center ) );
679 circle->SetEnd( RelPosSym( center + VECTOR2I( radius.x, 0 ) ) );
680
681 circle->SetUnit( 0 );
682 circle->SetStroke( STROKE_PARAMS( ScaleSize( lineWidth ), strokeStyle ) );
683
684 if( fillColor != wxS( "none" ) )
685 {
686 circle->SetFilled( true );
687
688 if( fillColor == strokeColor )
689 circle->SetFillMode( FILL_T::FILLED_SHAPE );
690 else
691 circle->SetFillMode( FILL_T::FILLED_WITH_BG_BODYCOLOR );
692 }
693
694 aSymbol->AddDrawItem( circle.release() );
695 }
696 else if( elType == wxS( "P" ) )
697 {
698 wxString sepShapeStr = shapeStr;
699 sepShapeStr.Replace( wxS( "^^" ), wxS( "\n" ) );
700
701 wxArrayString segments = wxSplit( sepShapeStr, '\n', '\0' );
702 wxArrayString mainParts = wxSplit( segments[0], '~', '\0' );
703 wxArrayString pinDotParts = wxSplit( segments[1], '~', '\0' );
704 wxArrayString pinPathColorParts = wxSplit( segments[2], '~', '\0' );
705 wxArrayString pinNameParts = wxSplit( segments[3], '~', '\0' );
706 wxArrayString pinNumParts = wxSplit( segments[4], '~', '\0' );
707
708 //bool show = mainParts[1].Lower() != wxS( "none" );
709 ELECTRICAL_PINTYPE elecType = ConvertElecType( mainParts[2] );
710 wxString pinNumber = mainParts[3];
711 VECTOR2D pinPos( Convert( mainParts[4] ), Convert( mainParts[5] ) );
712 //int pinRot = Convert( mainParts[6] );
713
714 VECTOR2D pinDotPos( Convert( pinDotParts[0] ), Convert( pinDotParts[1] ) );
715
716 bool nameVisible = pinNameParts[0] != wxS( "0" );
717 wxString pinName = pinNameParts[4];
718
719 bool numVisible = pinNumParts[0] != wxS( "0" );
720 wxString ptSize = pinNumParts[4];
721
722 VECTOR2D startPoint;
723 bool vertical = false;
724 double pinLen = 0;
725
726 // M360,290h10 or M 420 300 h -5
727 wxString lineData = pinPathColorParts[0];
728 wxRegEx regex( wxS( "^M\\s*([-\\d.]+)[,\\s]([-\\d.]+)\\s*([h|v])\\s*([-\\d.]+)\\s*$" ) );
729
730 if( regex.Matches( lineData ) )
731 {
732 startPoint.x = Convert( regex.GetMatch( lineData, 1 ) );
733 startPoint.y = Convert( regex.GetMatch( lineData, 2 ) );
734
735 vertical = regex.GetMatch( lineData, 3 ).Contains( wxS( "v" ) );
736 pinLen = Convert( regex.GetMatch( lineData, 4 ) );
737 }
738
739 int pinRotation = 0;
740
741 if( !vertical )
742 {
743 if( startPoint.x == pinPos.x && pinLen < 0 )
744 pinRotation = 180;
745 else if( startPoint.x == pinPos.x && pinLen > 0 )
746 pinRotation = 0;
747 else if( startPoint.x != pinPos.x && pinLen < 0 )
748 pinRotation = 0;
749 else if( startPoint.x != pinPos.x && pinLen > 0 )
750 pinRotation = 180;
751 }
752 else
753 {
754 if( startPoint.y == pinPos.y && pinLen < 0 )
755 pinRotation = 90;
756 else if( startPoint.y == pinPos.y && pinLen > 0 )
757 pinRotation = 270;
758 else if( startPoint.y != pinPos.y && pinLen < 0 )
759 pinRotation = 270;
760 else if( startPoint.y != pinPos.y && pinLen > 0 )
761 pinRotation = 90;
762 }
763
764 PIN_ORIENTATION orient = PIN_ORIENTATION::PIN_RIGHT;
765
766 if( pinRotation == 0 )
767 orient = PIN_ORIENTATION::PIN_RIGHT;
768 else if( pinRotation == 90 )
769 orient = PIN_ORIENTATION::PIN_UP;
770 else if( pinRotation == 180 )
771 orient = PIN_ORIENTATION::PIN_LEFT;
772 else if( pinRotation == 270 )
773 orient = PIN_ORIENTATION::PIN_DOWN;
774
775 int pinUnit = 0;
776 int kPinLen = ScaleSize( std::abs( pinLen ) );
777
778 if( segments.size() > 5 )
779 {
780 wxArrayString dotParts = wxSplit( segments[5], '~', '\0' );
781 wxArrayString clockParts = wxSplit( segments[6], '~', '\0' );
782
783 if( dotParts.size() == 3 && clockParts.size() == 2 )
784 {
785 if( dotParts[0] == wxS( "1" ) )
786 {
787 VECTOR2D dotPos( Convert( dotParts[1] ), Convert( dotParts[2] ) );
788
789 auto circle = std::make_unique<SCH_SHAPE>( SHAPE_T::CIRCLE, LAYER_DEVICE );
790
791 circle->SetCenter( RelPosSym( dotPos ) );
792 circle->SetEnd( RelPosSym(
793 pinPos + ( dotPos - pinPos ).Resize( std::abs( pinLen ) ) ) );
794
795 circle->SetUnit( 0 );
796
797 aSymbol->AddDrawItem( circle.release() );
798 }
799
800 if( clockParts[0] == wxS( "1" ) )
801 {
802 std::vector<SHAPE_LINE_CHAIN> lineChains =
803 ParseLineChains( clockParts[1], schIUScale.MilsToIU( 10 ), false );
804
805 for( SHAPE_LINE_CHAIN outline : lineChains )
806 {
807 auto shape = std::make_unique<SCH_SHAPE>( SHAPE_T::POLY, LAYER_DEVICE );
808
809 if( outline.IsClosed() )
810 outline.Append( outline.CPoint( 0 ), true );
811
812 for( const VECTOR2I& pt : outline.CPoints() )
813 shape->AddPoint( pt );
814
815 shape->SetUnit( 0 );
816
817 aSymbol->AddDrawItem( shape.release() );
818 }
819 }
820 }
821 }
822
823 std::unique_ptr<SCH_PIN> pin = std::make_unique<SCH_PIN>( aSymbol );
824
825 pin->SetName( pinName );
826 pin->SetNumber( pinNumber );
827 pin->SetOrientation( orient );
828 pin->SetType( elecType );
829 pin->SetLength( kPinLen );
830 pin->SetPosition( RelPosSym( pinPos ) );
831 pin->SetUnit( pinUnit );
832
833 if( pin->GetNumberTextSize() * int( pinNumber.size() ) > kPinLen )
834 pin->SetNumberTextSize( kPinLen / pinNumber.size() );
835
836 if( !nameVisible )
837 pin->SetNameTextSize( schIUScale.MilsToIU( 1 ) );
838
839 if( !numVisible )
840 pin->SetNumberTextSize( schIUScale.MilsToIU( 1 ) );
841
842 aSymbol->AddDrawItem( pin.release() );
843 }
844 else if( elType == wxS( "T" ) )
845 {
846 wxString textType = arr[1];
847 VECTOR2D pos( Convert( arr[2] ), Convert( arr[3] ) );
848 int angle = Convert( arr[4] );
849 wxString color = arr[5];
850 wxString fontname = arr[6];
851 wxString fontSize = arr[7];
852 wxString baselineAlign = arr[10];
853 wxString textStr = arr[12];
854 bool visible = arr[13] != wxS( "0" );
855
856 textStr.Replace( wxS( "\\n" ), wxS( "\n" ) );
857 textStr = UnescapeHTML( textStr );
858
859 wxString halignStr = arr[14]; // Empty, start, middle, end, inherit
860
861 bool added = false;
862 EDA_TEXT* textItem = nullptr;
863
864 if( textType == wxS( "P" ) )
865 {
866 textItem = &aSymbol->GetReferenceField();
867 textItem->SetTextPos( RelPosSym( pos ) );
868 textItem->SetText( textStr );
869 }
870 else if( textType == wxS( "N" ) )
871 {
872 textItem = &aSymbol->GetValueField();
873 textItem->SetTextPos( RelPosSym( pos ) );
874 textItem->SetText( textStr );
875 }
876 else
877 {
878 textItem = new SCH_TEXT( RelPosSym( pos ), textStr, LAYER_DEVICE );
879 added = true;
880 }
881
882 textItem->SetTextAngleDegrees( ( 360 - angle ) % 360 );
884
885 if( halignStr == wxS( "middle" ) )
887 else if( halignStr == wxS( "end" ) )
889 else
891
892 textItem->SetFont( KIFONT::FONT::GetFont( fontname ) );
893 textItem->SetVisible( visible );
894
895 double ptSize = 7;
896
897 if( !fontSize.IsEmpty() )
898 {
899 if( fontSize.EndsWith( wxS( "pt" ) ) )
900 ptSize = Convert( fontSize.BeforeFirst( 'p' ) );
901 else if( fontSize.IsNumber() )
902 ptSize = Convert( fontSize );
903 }
904
905 double ktextSize = ScaleSize( ptSize );
906
907 if( textStr.Contains( wxS( "\n" ) ) )
908 ktextSize *= 0.8;
909 else
910 ktextSize *= 0.95;
911
912 textItem->SetTextSize( VECTOR2I( ktextSize, ktextSize ) );
913
914 TransformTextToBaseline( textItem, baselineAlign );
915
916 if( added )
917 aSymbol->AddDrawItem( dynamic_cast<SCH_ITEM*>( textItem ) );
918 }
919 }
920}
921
922
924 std::map<wxString, wxString> aParams,
925 wxArrayString aShapes )
926{
927 std::unique_ptr<LIB_SYMBOL> ksymbol = std::make_unique<LIB_SYMBOL>( wxEmptyString );
928
929 m_relOrigin = aOrigin;
930
931 std::optional<wxString> valOpt;
932 wxString symbolName = wxS( "Unknown" );
933
934 if( ( valOpt = get_opt( aParams, wxS( "name" ) ) ) )
935 symbolName = *valOpt;
936 else if( ( valOpt = get_opt( aParams, wxS( "spiceSymbolName" ) ) ) )
937 symbolName = *valOpt;
938
939 wxString symbolPrefix;
940
941 if( ( valOpt = get_opt( aParams, wxS( "pre" ) ) ) )
942 symbolPrefix = *valOpt;
943 else if( ( valOpt = get_opt( aParams, wxS( "spicePre" ) ) ) )
944 symbolPrefix = *valOpt;
945
946 LIB_ID libId = EasyEdaToKiCadLibID( wxEmptyString, symbolName );
947
948 ksymbol->SetLibId( libId );
949 ksymbol->SetName( symbolName );
950
951 ksymbol->GetReferenceField().SetText( symbolPrefix );
952 ksymbol->GetValueField().SetText( symbolName );
953
954 for( wxString attrName : c_attributesWhitelist )
955 {
956 wxString srcName = attrName;
957
958 if( srcName == wxS( "Datasheet" ) )
959 srcName = wxS( "link" );
960
961 if( ( valOpt = get_opt( aParams, srcName ) ) )
962 {
963 if( valOpt->empty() )
964 continue;
965
966 SCH_FIELD* fd = ksymbol->FindField( attrName, true );
967
968 if( !fd )
969 {
970 fd = new SCH_FIELD( ksymbol.get(), ksymbol->GetNextAvailableFieldId(), attrName );
971 ksymbol->AddField( fd );
972 }
973
974 fd->SetText( *valOpt );
975 fd->SetVisible( false );
976 }
977 }
978
979 ParseSymbolShapes( ksymbol.get(), aParams, aShapes );
980
981 return ksymbol.release();
982}
983
984std::pair<LIB_SYMBOL*, bool> SCH_EASYEDA_PARSER::MakePowerSymbol( const wxString& aFlagTypename,
985 const wxString& aNetname )
986{
987 std::unique_ptr<LIB_SYMBOL> ksymbol = std::make_unique<LIB_SYMBOL>( wxEmptyString );
988
990
991 LIB_ID libId = EasyEdaToKiCadLibID( wxEmptyString, aNetname );
992
993 ksymbol->SetPower();
994 ksymbol->SetLibId( libId );
995 ksymbol->SetName( aNetname );
996 ksymbol->GetReferenceField().SetText( wxS( "#PWR" ) );
997 ksymbol->GetReferenceField().SetVisible( false );
998 ksymbol->GetValueField().SetText( aNetname );
999 ksymbol->GetValueField().SetVisible( true );
1000 ksymbol->SetDescription( wxString::Format( _( "Power symbol creates a global "
1001 "label with name '%s'" ),
1002 aNetname ) );
1003 ksymbol->SetKeyWords( wxS( "power-flag" ) );
1004 ksymbol->SetShowPinNames( false );
1005 ksymbol->SetShowPinNumbers( false );
1006
1007 std::unique_ptr<SCH_PIN> pin = std::make_unique<SCH_PIN>( ksymbol.get() );
1008
1009 pin->SetName( aNetname );
1010 pin->SetNumber( wxS( "1" ) );
1011 pin->SetOrientation( PIN_ORIENTATION::PIN_DOWN );
1012 pin->SetType( ELECTRICAL_PINTYPE::PT_POWER_IN );
1013 pin->SetLength( 0 );
1014
1015 ksymbol->AddDrawItem( pin.release() );
1016
1018
1019 bool flip = false;
1020
1021 if( aFlagTypename == wxS( "part_netLabel_gnD" ) )
1022 {
1024 }
1025 else if( aFlagTypename == wxS( "part_netLabel_GNd" ) )
1026 {
1028 }
1029 else if( aFlagTypename == wxS( "part_netLabel_gNd" ) )
1030 {
1032 }
1033 else if( aFlagTypename == wxS( "part_netLabel_GnD" ) )
1034 {
1036 }
1037 else if( aFlagTypename == wxS( "part_netLabel_VCC" ) )
1038 {
1040 flip = true;
1041 }
1042 else if( aFlagTypename == wxS( "part_netLabel_+5V" ) )
1043 {
1045 flip = true;
1046 }
1047 else if( aFlagTypename == wxS( "part_netLabel_VEE" ) )
1048 {
1050 }
1051 else if( aFlagTypename == wxS( "part_netLabel_-5V" ) )
1052 {
1054 }
1055 else if( aFlagTypename == wxS( "part_netLabel_Bar" ) )
1056 {
1058 flip = true;
1059 }
1060
1061 VECTOR2I valueFieldPos = HelperGeneratePowerPortGraphics( ksymbol.get(), flagStyle, nullptr );
1062 ksymbol->GetValueField().SetPosition( valueFieldPos );
1063
1064 return std::make_pair( ksymbol.release(), flip );
1065}
1066
1068 const wxString& aFileName, wxArrayString aShapes )
1069{
1070 std::map<wxString, std::unique_ptr<LIB_SYMBOL>> loadedSymbols;
1071 std::map<wxString, int> namesCounter;
1072 std::vector<std::unique_ptr<SCH_ITEM>> createdItems;
1073
1074 for( wxString shap : aShapes )
1075 {
1076 shap.Replace( wxS( "#@$" ), wxS( "\n" ) );
1077 wxArrayString parts = wxSplit( shap, '\n', '\0' );
1078
1079 if( parts.size() < 1 )
1080 continue;
1081
1082 wxArrayString arr = wxSplit( parts[0], '~', '\0' );
1083
1084 if( arr.size() < 1 )
1085 continue;
1086
1087 wxString rootType = arr[0];
1088
1089 if( rootType == wxS( "LIB" ) )
1090 {
1091 if( arr.size() < 4 )
1092 continue;
1093
1094 VECTOR2D origin( Convert( arr[1] ), Convert( arr[2] ) );
1095
1096 wxString symbolName = wxString::Format( wxS( "Unknown_%s_%s" ), arr[1], arr[2] );
1097
1098 wxArrayString paramParts = wxSplit( arr[3], '`', '\0' );
1099
1100 std::map<wxString, wxString> paramMap;
1101
1102 for( size_t i = 1; i < paramParts.size(); i += 2 )
1103 {
1104 wxString key = paramParts[i - 1];
1105 wxString value = paramParts[i];
1106
1107 if( key == wxS( "spiceSymbolName" ) && !value.IsEmpty() )
1108 symbolName = value;
1109
1110 paramMap[key] = value;
1111 }
1112
1113 int& serial = namesCounter[symbolName];
1114
1115 if( serial > 0 )
1116 symbolName << wxS( "_" ) << serial;
1117
1118 serial++;
1119
1120 paramMap[wxS( "spiceSymbolName" )] = symbolName;
1121
1122 parts.RemoveAt( 0 );
1123
1124 VECTOR2D pcbOrigin = m_relOrigin;
1125
1126 LIB_SYMBOL* sym = ParseSymbol( origin, paramMap, parts );
1127 loadedSymbols.emplace( symbolName, sym );
1128
1129 wxString referenceStr = sym->GetReferenceField().GetText();
1130
1131 m_relOrigin = pcbOrigin;
1132 LIB_ID libId = EasyEdaToKiCadLibID( wxEmptyString, symbolName );
1133
1134 std::unique_ptr<SCH_SYMBOL> schSym =
1135 std::make_unique<SCH_SYMBOL>( *sym, libId, &aSchematic->CurrentSheet(), 0 );
1136
1137 schSym->SetPosition( RelPos( origin ) );
1138 schSym->SetRef( &aSchematic->CurrentSheet(), referenceStr );
1139
1140 createdItems.push_back( std::move( schSym ) );
1141 }
1142 else if( rootType == wxS( "F" ) )
1143 {
1144 wxString sepShapeStr = parts[0];
1145 sepShapeStr.Replace( wxS( "^^" ), wxS( "\n" ) );
1146
1147 wxArrayString segments = wxSplit( sepShapeStr, '\n', '\0' );
1148 wxArrayString mainParts = wxSplit( segments[0], '~', '\0' );
1149 wxArrayString uselessParts = wxSplit( segments[1], '~', '\0' );
1150 wxArrayString valueParts = wxSplit( segments[2], '~', '\0' );
1151
1152 wxString flagTypename = arr[1];
1153 VECTOR2D pos( Convert( arr[2] ), Convert( arr[3] ) );
1154 double angle = Convert( arr[4] );
1155
1156 wxString netnameValue = valueParts[0];
1157 VECTOR2D valuePos( Convert( valueParts[2] ), Convert( valueParts[3] ) );
1158 double textAngle = Convert( valueParts[4] );
1159 wxString halignStr = valueParts[5];
1160 wxString valueFontname = valueParts[7];
1161 wxString valueFontsize = valueParts[8];
1162
1163 if( flagTypename == wxS( "part_netLabel_netPort" ) )
1164 {
1165 std::unique_ptr<SCH_GLOBALLABEL> label =
1166 std::make_unique<SCH_GLOBALLABEL>( RelPos( pos ), netnameValue );
1167
1169
1170 for( double i = angle; i > 0; i -= 90 )
1171 spin = spin.RotateCCW();
1172
1173 // If the shape was mirrored, we can't rely on angle value to determine direction.
1174 if( segments.size() > 3 )
1175 {
1176 wxArrayString shapeParts = wxSplit( segments[3], '~', '\0' );
1177 if( shapeParts[0] == wxS( "PL" ) )
1178 {
1179 wxArrayString ptArr = wxSplit( shapeParts[1], ' ', '\0' );
1180
1181 SHAPE_LINE_CHAIN chain;
1182
1183 for( size_t i = 1; i < ptArr.size(); i += 2 )
1184 {
1185 chain.Append( RelPos(
1186 VECTOR2I( Convert( ptArr[i - 1] ), Convert( ptArr[i] ) ) ) );
1187 }
1188
1189 chain.Move( -RelPos( pos ) );
1190
1191 VECTOR2I shapeCenter = chain.Centre();
1192
1193 if( std::abs( shapeCenter.x ) >= std::abs( shapeCenter.y ) )
1194 {
1195 if( shapeCenter.x >= 0 )
1196 spin = SPIN_STYLE::RIGHT;
1197 else
1198 spin = SPIN_STYLE::LEFT;
1199 }
1200 else
1201 {
1202 if( shapeCenter.y >= 0 )
1203 spin = SPIN_STYLE::BOTTOM;
1204 else
1205 spin = SPIN_STYLE::UP;
1206 }
1207 }
1208 }
1209
1210 label->SetSpinStyle( spin );
1211 label->SetShape( LABEL_FLAG_SHAPE::L_INPUT );
1212
1213 createdItems.push_back( std::move( label ) );
1214 }
1215 else
1216 {
1217 auto pair = MakePowerSymbol( flagTypename, netnameValue );
1218 LIB_SYMBOL* pwrLibSym = pair.first;
1219 bool flip = pair.second;
1220
1221 LIB_ID libId = EasyEdaToKiCadLibID( wxEmptyString, netnameValue );
1222
1223 std::unique_ptr<SCH_SYMBOL> schSym = std::make_unique<SCH_SYMBOL>(
1224 *pwrLibSym, libId, &aSchematic->CurrentSheet(), 0 );
1225
1226 if( flip )
1227 schSym->SetOrientation( SYM_MIRROR_X );
1228
1229 if( angle == 0 )
1230 {
1231 }
1232 else if( angle == 90 )
1233 {
1234 schSym->SetOrientation( SYM_ROTATE_COUNTERCLOCKWISE );
1235 }
1236 if( angle == 180 )
1237 {
1238 schSym->SetOrientation( SYM_ROTATE_COUNTERCLOCKWISE );
1239 schSym->SetOrientation( SYM_ROTATE_COUNTERCLOCKWISE );
1240 }
1241 if( angle == 270 )
1242 {
1243 schSym->SetOrientation( SYM_ROTATE_CLOCKWISE );
1244 }
1245
1246 schSym->SetPosition( RelPos( pos ) );
1247
1248 SCH_FIELD* valField = schSym->GetField( VALUE_FIELD );
1249
1250 valField->SetPosition( RelPos( valuePos ) );
1251 valField->SetTextAngleDegrees( textAngle - angle );
1252
1253 if( !flip )
1255 else
1257
1258 if( halignStr == wxS( "middle" ) )
1260 else if( halignStr == wxS( "end" ) )
1262 else
1264
1265 if( flip && ( angle == 90 || angle == 270 ) )
1266 {
1267 if( valField->GetVertJustify() == GR_TEXT_V_ALIGN_BOTTOM )
1269 else if( valField->GetVertJustify() == GR_TEXT_V_ALIGN_TOP )
1271
1272 if( valField->GetHorizJustify() == GR_TEXT_H_ALIGN_RIGHT )
1274 else if( valField->GetHorizJustify() == GR_TEXT_H_ALIGN_LEFT )
1276
1277 if( flagTypename == wxS( "part_netLabel_Bar" ) ) // "Circle"
1279 }
1280
1281 if( angle == 0 && flagTypename == wxS( "part_netLabel_Bar" ) ) // "Circle"
1283
1284 valField->SetFont( KIFONT::FONT::GetFont( valueFontname ) );
1285
1286 double ptSize = 7;
1287
1288 if( valueFontsize.EndsWith( wxS( "pt" ) ) )
1289 ptSize = Convert( valueFontsize.BeforeFirst( 'p' ) );
1290
1291 double ktextSize = ScaleSize( ptSize );
1292
1293 if( netnameValue.Contains( wxS( "\n" ) ) )
1294 ktextSize *= 0.8;
1295 else
1296 ktextSize *= 0.95;
1297
1298 valField->SetTextSize( VECTOR2I( ktextSize, ktextSize ) );
1299
1300 //TransformTextToBaseline( valField, wxS( "" ), true );
1301
1302 createdItems.push_back( std::move( schSym ) );
1303 }
1304 }
1305 else if( rootType == wxS( "W" ) )
1306 {
1307 wxArrayString ptArr = wxSplit( arr[1], ' ', '\0' );
1308 wxString strokeColor = arr[2];
1309 //double lineWidth = Convert( arr[3] );
1310 //LINE_STYLE strokeStyle = ConvertStrokeStyle( arr[4] );
1311 wxString fillColor = arr[5].Lower();
1312 //bool locked = arr[7] != wxS( "0" );
1313
1314 SHAPE_LINE_CHAIN chain;
1315
1316 for( size_t i = 1; i < ptArr.size(); i += 2 )
1317 chain.Append( VECTOR2I( RelPosX( ptArr[i - 1] ), RelPosY( ptArr[i] ) ) );
1318
1319 for( int segId = 0; segId < chain.SegmentCount(); segId++ )
1320 {
1321 const SEG& seg = chain.CSegment( segId );
1322
1323 std::unique_ptr<SCH_LINE> line = std::make_unique<SCH_LINE>( seg.A, LAYER_WIRE );
1324 line->SetEndPoint( seg.B );
1325
1326 createdItems.push_back( std::move( line ) );
1327 }
1328 }
1329 else if( rootType == wxS( "N" ) )
1330 {
1331 VECTOR2D pos( Convert( arr[1] ), Convert( arr[2] ) );
1332 double angle = Convert( arr[3] );
1333 wxString netname = arr[5];
1334 wxString halignStr = arr[7];
1335 VECTOR2D text_pos( Convert( arr[8] ),
1336 Convert( arr[9] ) ); // TODO: detect top/bottom align
1337
1338 wxString fontname = arr[10];
1339 wxString fontSize = arr[11];
1340
1341 std::unique_ptr<SCH_LABEL> label =
1342 std::make_unique<SCH_LABEL>( RelPos( pos ), netname );
1343
1344 if( halignStr == wxS( "middle" ) )
1345 label->SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
1346 else if( halignStr == wxS( "end" ) )
1347 label->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
1348 else
1349 label->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
1350
1351 for( int left = angle; left > 0; left -= 90 )
1352 label->Rotate90( false );
1353
1354 createdItems.push_back( std::move( label ) );
1355 }
1356 else if( rootType == wxS( "O" ) )
1357 {
1358 VECTOR2D pos( Convert( arr[1] ), Convert( arr[2] ) );
1359
1360 std::unique_ptr<SCH_NO_CONNECT> noConn =
1361 std::make_unique<SCH_NO_CONNECT>( RelPos( pos ) );
1362
1363 createdItems.push_back( std::move( noConn ) );
1364 }
1365 else if( rootType == wxS( "J" ) )
1366 {
1367 VECTOR2D pos( Convert( arr[1] ), Convert( arr[2] ) );
1368 //double dia = Convert( arr[3] );
1369
1370 std::unique_ptr<SCH_JUNCTION> junction =
1371 std::make_unique<SCH_JUNCTION>( RelPos( pos ) /*, ScaleSizeUnit( dia )*/ );
1372
1373 createdItems.push_back( std::move( junction ) );
1374 }
1375 else if( rootType == wxS( "T" ) )
1376 {
1377 VECTOR2D pos( Convert( arr[2] ), Convert( arr[3] ) );
1378 int angle = Convert( arr[4] );
1379 wxString color = arr[5];
1380 wxString fontname = arr[6];
1381 wxString fontSize = arr[7];
1382 wxString baselineAlign = arr[10];
1383 wxString textStr = arr[12];
1384
1385 textStr.Replace( wxS( "\\n" ), wxS( "\n" ) );
1386 textStr = UnescapeHTML( textStr );
1387
1388 wxString halignStr = arr[14]; // Empty, start, middle, end, inherit
1389
1390 std::unique_ptr<SCH_TEXT> textItem =
1391 std::make_unique<SCH_TEXT>( RelPos( pos ), textStr );
1392
1393 textItem->SetTextAngleDegrees( ( 360 - angle ) % 360 );
1394 textItem->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
1395
1396 if( halignStr == wxS( "middle" ) )
1397 textItem->SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
1398 else if( halignStr == wxS( "end" ) )
1399 textItem->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
1400 else
1401 textItem->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
1402
1403 textItem->SetFont( KIFONT::FONT::GetFont( fontname ) );
1404
1405 double ptSize = 7;
1406
1407 if( fontSize.EndsWith( wxS( "pt" ) ) )
1408 ptSize = Convert( fontSize.BeforeFirst( 'p' ) );
1409
1410 double ktextSize = ScaleSize( ptSize );
1411
1412 if( textStr.Contains( wxS( "\n" ) ) )
1413 ktextSize *= 0.8;
1414 else
1415 ktextSize *= 0.95;
1416
1417 textItem->SetTextSize( VECTOR2I( ktextSize, ktextSize ) );
1418
1419 TransformTextToBaseline( textItem.get(), baselineAlign );
1420
1421 createdItems.push_back( std::move( textItem ) );
1422 }
1423 else if( rootType == wxS( "R" ) )
1424 {
1425 VECTOR2D start( Convert( arr[1] ), Convert( arr[2] ) );
1426
1427 VECTOR2D cr;
1428 cr.x = !arr[3].empty() ? Convert( arr[3] ) : 0,
1429 cr.y = !arr[4].empty() ? Convert( arr[4] ) : 0; // TODO: corner radius
1430
1431 VECTOR2D size( Convert( arr[5] ), Convert( arr[6] ) );
1432 wxString strokeColor = arr[7];
1433 double lineWidth = Convert( arr[8] );
1434 LINE_STYLE strokeStyle = ConvertStrokeStyle( arr[9] );
1435 wxString fillColor = arr[10].Lower();
1436 //bool locked = arr[12] != wxS( "0" );
1437
1438 //if( cr.x == 0 )
1439 {
1440 std::unique_ptr<SCH_SHAPE> rect = std::make_unique<SCH_SHAPE>( SHAPE_T::RECTANGLE );
1441
1442 rect->SetStart( RelPos( start ) );
1443 rect->SetEnd( RelPos( start + size ) );
1444
1445 rect->SetStroke( STROKE_PARAMS( ScaleSize( lineWidth ), strokeStyle ) );
1446
1447 if( fillColor != wxS( "none" ) )
1448 {
1449 rect->SetFilled( true );
1450
1451 if( fillColor == strokeColor )
1452 rect->SetFillMode( FILL_T::FILLED_SHAPE );
1453 else
1454 rect->SetFillMode( FILL_T::FILLED_WITH_BG_BODYCOLOR );
1455 }
1456
1457 createdItems.push_back( std::move( rect ) );
1458 }
1459 /*else
1460 {
1461 }*/
1462 }
1463 else if( rootType == wxS( "I" ) )
1464 {
1465 VECTOR2D start( Convert( arr[1] ), Convert( arr[2] ) );
1466 VECTOR2D size( Convert( arr[3] ), Convert( arr[4] ) );
1467 //double angle = Convert( arr[5] ); // CSS-like transformations are used instead.
1468 wxString imageUrl = arr[6];
1469 wxString transformData = arr[9];
1470
1471 VECTOR2D kstart = RelPos( start );
1472 VECTOR2D ksize = ScalePos( size );
1473
1474 std::vector<std::pair<wxString, std::vector<double>>> transformCmds =
1475 ParseImageTransform( transformData );
1476
1477 auto applyTransform = [&]( SCH_ITEM* aSchItem )
1478 {
1479 for( const auto& cmd : transformCmds )
1480 {
1481 if( cmd.first == wxS( "rotate" ) )
1482 {
1483 if( cmd.second.size() != 3 )
1484 continue;
1485
1486 double cmdAngle = 360 - cmd.second[0];
1487 VECTOR2D cmdAround( cmd.second[1], cmd.second[2] );
1488
1489 for( double i = cmdAngle; i > 0; i -= 90 )
1490 {
1491 if( aSchItem->Type() == SCH_LINE_T )
1492 {
1493 // Lines need special handling for some reason
1494 aSchItem->SetFlags( STARTPOINT );
1495 aSchItem->Rotate( RelPos( cmdAround ), false );
1496 aSchItem->ClearFlags( STARTPOINT );
1497
1498 aSchItem->SetFlags( ENDPOINT );
1499 aSchItem->Rotate( RelPos( cmdAround ), false );
1500 aSchItem->ClearFlags( ENDPOINT );
1501 }
1502 else
1503 {
1504 aSchItem->Rotate( RelPos( cmdAround ), false );
1505 }
1506 }
1507 }
1508 else if( cmd.first == wxS( "translate" ) )
1509 {
1510 if( cmd.second.size() != 2 )
1511 continue;
1512
1513 VECTOR2D cmdOffset( cmd.second[0], cmd.second[1] );
1514 aSchItem->Move( ScalePos( cmdOffset ) );
1515 }
1516 else if( cmd.first == wxS( "scale" ) )
1517 {
1518 if( cmd.second.size() != 2 )
1519 continue;
1520
1521 double cmdScaleX = cmd.second[0];
1522 double cmdScaleY = cmd.second[1];
1523
1524 // Lines need special handling for some reason
1525 if( aSchItem->Type() == SCH_LINE_T )
1526 aSchItem->SetFlags( STARTPOINT | ENDPOINT );
1527
1528 if( cmdScaleX < 0 && cmdScaleY > 0 )
1529 {
1530 aSchItem->MirrorHorizontally( 0 );
1531 }
1532 else if( cmdScaleX > 0 && cmdScaleY < 0 )
1533 {
1534 aSchItem->MirrorVertically( 0 );
1535 }
1536 else if( cmdScaleX < 0 && cmdScaleY < 0 )
1537 {
1538 aSchItem->MirrorHorizontally( 0 );
1539 aSchItem->MirrorVertically( 0 );
1540 }
1541
1542 if( aSchItem->Type() == SCH_LINE_T )
1543 aSchItem->ClearFlags( STARTPOINT | ENDPOINT );
1544 }
1545 }
1546 };
1547
1548 if( imageUrl.BeforeFirst( ':' ) == wxS( "data" ) )
1549 {
1550 wxArrayString paramsArr =
1551 wxSplit( imageUrl.AfterFirst( ':' ).BeforeFirst( ',' ), ';', '\0' );
1552
1553 wxString data = imageUrl.AfterFirst( ',' );
1554
1555 if( paramsArr.size() > 0 )
1556 {
1557 wxString mimeType = paramsArr[0];
1558 wxMemoryBuffer buf = wxBase64Decode( data );
1559
1560 if( mimeType == wxS( "image/svg+xml" ) )
1561 {
1562 VECTOR2D offset = RelPos( start );
1563
1564 SVG_IMPORT_PLUGIN svgImportPlugin;
1565 GRAPHICS_IMPORTER_SCH schImporter;
1566
1567 svgImportPlugin.SetImporter( &schImporter );
1568 svgImportPlugin.LoadFromMemory( buf );
1569
1570 VECTOR2D imSize( svgImportPlugin.GetImageWidth(),
1571 svgImportPlugin.GetImageHeight() );
1572
1573 VECTOR2D pixelScale( schIUScale.IUTomm( ScaleSize( size.x ) ) / imSize.x,
1574 schIUScale.IUTomm( ScaleSize( size.y ) ) / imSize.y );
1575
1576 schImporter.SetScale( pixelScale );
1577
1578 VECTOR2D offsetMM( schIUScale.IUTomm( offset.x ),
1579 schIUScale.IUTomm( offset.y ) );
1580
1581 schImporter.SetImportOffsetMM( offsetMM );
1582
1583 svgImportPlugin.Import();
1584
1585 for( std::unique_ptr<EDA_ITEM>& item : schImporter.GetItems() )
1586 {
1587 SCH_ITEM* schItem = static_cast<SCH_ITEM*>( item.release() );
1588
1589 applyTransform( schItem );
1590
1591 createdItems.emplace_back( schItem );
1592 }
1593 }
1594 else
1595 {
1596 std::unique_ptr<SCH_BITMAP> bitmap = std::make_unique<SCH_BITMAP>();
1597
1598 wxImage::SetDefaultLoadFlags( wxImage::GetDefaultLoadFlags()
1599 & ~wxImage::Load_Verbose );
1600
1601 if( bitmap->ReadImageFile( buf ) )
1602 {
1603 VECTOR2D kcenter = kstart + ksize / 2;
1604
1605 double scaleFactor = ScaleSize( size.x ) / bitmap->GetSize().x;
1606 bitmap->SetImageScale( scaleFactor );
1607 bitmap->SetPosition( kcenter );
1608
1609 applyTransform( bitmap.get() );
1610
1611 createdItems.push_back( std::move( bitmap ) );
1612 }
1613 }
1614 }
1615 }
1616 }
1617 }
1618
1619 BOX2I sheetBBox;
1620
1621 for( std::unique_ptr<SCH_ITEM>& ptr : createdItems )
1622 if( ptr->Type() == SCH_SYMBOL_T )
1623 sheetBBox.Merge( static_cast<SCH_SYMBOL*>( ptr.get() )->GetBodyBoundingBox() );
1624
1625 SCH_SCREEN* screen = aRootSheet->GetScreen();
1626 PAGE_INFO pageInfo = screen->GetPageSettings();
1627
1628 int alignGrid = schIUScale.MilsToIU( 50 );
1629
1630 VECTOR2D offset( -sheetBBox.GetLeft(), -sheetBBox.GetTop() );
1631 offset.x = KiROUND( offset.x / alignGrid ) * alignGrid;
1632 offset.y = KiROUND( offset.y / alignGrid ) * alignGrid;
1633
1634 pageInfo.SetWidthMils( schIUScale.IUToMils( sheetBBox.GetWidth() ) );
1635 pageInfo.SetHeightMils( schIUScale.IUToMils( sheetBBox.GetHeight() ) );
1636
1637 screen->SetPageSettings( pageInfo );
1638
1639 for( std::unique_ptr<SCH_ITEM>& ptr : createdItems )
1640 {
1641 ptr->Move( offset );
1642 screen->Append( ptr.release() );
1643 }
1644}
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
std::vector< SHAPE_LINE_CHAIN > ParseLineChains(const wxString &aData, int aArcMinSegLen, bool aForceClosed)
static double Convert(const wxString &aValue)
double RelPosX(double aValue)
double RelPosY(double aValue)
VECTOR2< T > RelPos(const VECTOR2< T > &aVec)
VECTOR2< T > ScalePos(const VECTOR2< T > &aValue)
void TransformTextToBaseline(EDA_TEXT *textItem, const wxString &baselineAlign)
void SetEnd(const VECTOR2I &aEnd)
Definition: eda_shape.h:166
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:83
void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true)
Definition: eda_text.cpp:372
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:98
void SetTextPos(const VECTOR2I &aPoint)
Definition: eda_text.cpp:417
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
Definition: eda_text.cpp:274
GR_TEXT_H_ALIGN_T GetHorizJustify() const
Definition: eda_text.h:164
virtual void SetVisible(bool aVisible)
Definition: eda_text.cpp:243
void SetTextAngleDegrees(double aOrientation)
Definition: eda_text.h:137
GR_TEXT_V_ALIGN_T GetVertJustify() const
Definition: eda_text.h:167
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:181
void SetFont(KIFONT::FONT *aFont)
Definition: eda_text.cpp:356
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition: eda_text.cpp:266
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 logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:49
int Parse(const UTF8 &aId, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition: lib_id.cpp:51
Define a library symbol object.
Definition: lib_symbol.h:77
SCH_FIELD & GetValueField() const
Return reference to the value field.
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.
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:71
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)=0
Report a string with a given severity.
Holds all the data relating to one schematic.
Definition: schematic.h:75
SCH_SHEET_PATH & CurrentSheet() const override
Definition: schematic.h:136
void ParseSymbolShapes(LIB_SYMBOL *aContainer, std::map< wxString, wxString > paramMap, wxArrayString aShapes)
std::pair< LIB_SYMBOL *, bool > MakePowerSymbol(const wxString &aFlagTypename, const wxString &aNetname)
double ScaleSize(double aValue) override
void ParseSchematic(SCHEMATIC *aSchematic, SCH_SHEET *aRootSheet, const wxString &aFileName, wxArrayString aShapes)
VECTOR2< T > RelPosSym(const VECTOR2< T > &aVec)
LIB_SYMBOL * ParseSymbol(const VECTOR2D &aOrigin, std::map< wxString, wxString > aParams, wxArrayString aShapes)
SCH_EASYEDA_PARSER(SCHEMATIC *aSchematic, PROGRESS_REPORTER *aProgressReporter)
Instances are attached to a symbol or sheet and provide a place for the symbol's value,...
Definition: sch_field.h:51
void SetPosition(const VECTOR2I &aPosition) override
Definition: sch_field.cpp:1387
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
const PAGE_INFO & GetPageSettings() const
Definition: sch_screen.h:130
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Definition: sch_screen.cpp:151
void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition: sch_screen.h:131
void SetPosition(const VECTOR2I &aPos) override
Definition: sch_shape.h:71
void SetStroke(const STROKE_PARAMS &aStroke) override
Definition: sch_shape.cpp:63
void AddPoint(const VECTOR2I &aPosition)
Definition: sch_shape.cpp:576
VECTOR2I GetPosition() const override
Definition: sch_shape.h:70
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 GetBodyBoundingBox() const
Return a bounding box for the symbol body but not the pins or fields.
Definition: seg.h:42
VECTOR2I A
Definition: seg.h:49
VECTOR2I B
Definition: seg.h:50
const VECTOR2I & GetArcMid() const
Definition: shape_arc.h:115
const VECTOR2I & GetP1() const
Definition: shape_arc.h:114
const VECTOR2I & GetP0() const
Definition: shape_arc.h:113
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void Move(const VECTOR2I &aVector) override
bool IsClosed() const override
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
int PointCount() const
Return the number of points (vertices) in this line chain.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in 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.
virtual VECTOR2I Centre() const
Compute a center-of-mass of the shape.
Definition: shape.h:232
SPIN_STYLE RotateCCW()
Definition: sch_label.cpp:157
Simple container to manage line stroke parameters.
Definition: stroke_params.h:81
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.
#define _(s)
#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)
@ LAYER_DEVICE
Definition: layer_ids.h:370
@ LAYER_WIRE
Definition: layer_ids.h:356
std::optional< V > get_opt(const std::map< wxString, V > &aMap, const wxString &aKey)
Definition: map_helpers.h:34
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:424
ELECTRICAL_PINTYPE
The symbol library pin object electrical types used in ERC tests.
Definition: pin_type.h:36
@ PT_INPUT
usual pin input: must be connected
@ PT_OUTPUT
usual output
@ PT_BIDI
input or output (like port for a microprocessor)
@ PT_UNSPECIFIED
unknown electrical properties: creates always a warning when connected
@ PT_PASSIVE
pin for passive symbols: must be connected, and can be connected to any pin
PIN_ORIENTATION
The symbol library pin object orientations.
Definition: pin_type.h:77
@ RPT_SEVERITY_WARNING
static std::vector< std::vector< wxString > > RegexMatchAll(wxRegEx &aRegex, const wxString &aString)
static const std::vector< wxString > c_attributesWhitelist
static ELECTRICAL_PINTYPE ConvertElecType(const wxString &aType)
VECTOR2I HelperGeneratePowerPortGraphics(LIB_SYMBOL *aKsymbol, EASYEDA::POWER_FLAG_STYLE aStyle, REPORTER *aReporter)
static LIB_ID EasyEdaToKiCadLibID(const wxString &aLibName, const wxString &aLibReference)
static std::vector< std::pair< wxString, std::vector< double > > > ParseImageTransform(const wxString &transformData)
EasyEDA image transformations are in the form of:
static LINE_STYLE ConvertStrokeStyle(const wxString &aStyle)
VECTOR2I HelperGeneratePowerPortGraphics(LIB_SYMBOL *aKsymbol, ASCH_POWER_PORT_STYLE aStyle, REPORTER *aReporter)
@ SYM_ROTATE_CLOCKWISE
Definition: sch_symbol.h:79
@ SYM_ROTATE_COUNTERCLOCKWISE
Definition: sch_symbol.h:80
@ SYM_MIRROR_X
Definition: sch_symbol.h:85
const int scale
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
wxString UnescapeHTML(const wxString &aString)
Return a new wxString unescaped from HTML format.
@ CTX_LIBID
Definition: string_utils.h:54
LINE_STYLE
Dashed line types.
Definition: stroke_params.h:48
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".
@ GR_TEXT_H_ALIGN_CENTER
@ GR_TEXT_H_ALIGN_RIGHT
@ GR_TEXT_H_ALIGN_LEFT
@ GR_TEXT_V_ALIGN_BOTTOM
@ GR_TEXT_V_ALIGN_CENTER
@ GR_TEXT_V_ALIGN_TOP
@ 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