KiCad PCB EDA Suite
Loading...
Searching...
No Matches
kicad_diff_types.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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 3
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/gpl-3.0.html
19 */
20
22
23#include <core/wx_stl_compat.h>
24#include <eda_units.h>
25#include <geometry/eda_angle.h>
26#include <json_conversions.h>
27#include <layer_ids.h>
28
29#include <nlohmann/json.hpp>
30
31#include <wx/string.h>
32#include <wx/crt.h>
33#include <wx/file.h>
34
35#include <functional>
36#include <cstdio>
37#include <sstream>
38#include <stdexcept>
39
40#ifdef __WINDOWS__
41template class KICOMMON_API nlohmann::basic_json<>;
42#endif
43
44
45namespace KICAD_DIFF
46{
47
48namespace
49{
50
51// Tag strings used in JSON output. Keep stable; changing these is a wire-format break.
52constexpr const char* TYPE_NONE = "none";
53constexpr const char* TYPE_BOOL = "bool";
54constexpr const char* TYPE_INT = "int";
55constexpr const char* TYPE_INT64 = "int64";
56constexpr const char* TYPE_DOUBLE = "double";
57constexpr const char* TYPE_STRING = "string";
58constexpr const char* TYPE_KIID = "kiid";
59constexpr const char* TYPE_VECTOR2I = "vec2";
60constexpr const char* TYPE_BOX2I = "box2";
61constexpr const char* TYPE_COLOR = "color";
62constexpr const char* TYPE_LAYER = "layer";
63constexpr const char* TYPE_ENUM = "enum";
64constexpr const char* TYPE_POLYSET = "polyset";
65
66
67const char* typeTag( DIFF_VALUE::T aType )
68{
69 switch( aType )
70 {
71 case DIFF_VALUE::T::NONE: return TYPE_NONE;
72 case DIFF_VALUE::T::BOOL: return TYPE_BOOL;
73 case DIFF_VALUE::T::INT: return TYPE_INT;
74 case DIFF_VALUE::T::INT64: return TYPE_INT64;
75 case DIFF_VALUE::T::DOUBLE: return TYPE_DOUBLE;
76 case DIFF_VALUE::T::STRING: return TYPE_STRING;
77 case DIFF_VALUE::T::KIID: return TYPE_KIID;
78 case DIFF_VALUE::T::VECTOR2I: return TYPE_VECTOR2I;
79 case DIFF_VALUE::T::BOX2I: return TYPE_BOX2I;
80 case DIFF_VALUE::T::COLOR: return TYPE_COLOR;
81 case DIFF_VALUE::T::LAYER: return TYPE_LAYER;
82 case DIFF_VALUE::T::ENUM: return TYPE_ENUM;
83 case DIFF_VALUE::T::POLYGON_SET: return TYPE_POLYSET;
84 }
85
86 return TYPE_NONE;
87}
88
89
90DIFF_VALUE::T typeFromTag( const std::string& aTag )
91{
92 if( aTag == TYPE_BOOL ) return DIFF_VALUE::T::BOOL;
93 if( aTag == TYPE_INT ) return DIFF_VALUE::T::INT;
94 if( aTag == TYPE_INT64 ) return DIFF_VALUE::T::INT64;
95 if( aTag == TYPE_DOUBLE ) return DIFF_VALUE::T::DOUBLE;
96 if( aTag == TYPE_STRING ) return DIFF_VALUE::T::STRING;
97 if( aTag == TYPE_KIID ) return DIFF_VALUE::T::KIID;
98 if( aTag == TYPE_VECTOR2I ) return DIFF_VALUE::T::VECTOR2I;
99 if( aTag == TYPE_BOX2I ) return DIFF_VALUE::T::BOX2I;
100 if( aTag == TYPE_COLOR ) return DIFF_VALUE::T::COLOR;
101 if( aTag == TYPE_LAYER ) return DIFF_VALUE::T::LAYER;
102 if( aTag == TYPE_ENUM ) return DIFF_VALUE::T::ENUM;
103 if( aTag == TYPE_POLYSET )
104 return DIFF_VALUE::T::POLYGON_SET;
105
106 return DIFF_VALUE::T::NONE;
107}
108
109} // namespace
110
111
113{
114 DIFF_VALUE v;
115 v.m_type = T::BOOL;
116 v.m_value = aValue;
117 return v;
118}
119
120
122{
123 DIFF_VALUE v;
124 v.m_type = T::INT;
125 v.m_value = aValue;
126 return v;
127}
128
129
131{
132 DIFF_VALUE v;
133 v.m_type = T::INT64;
134 v.m_value = aValue;
135 return v;
136}
137
138
140{
141 DIFF_VALUE v;
142 v.m_type = T::DOUBLE;
143 v.m_value = aValue;
144 return v;
145}
146
147
148DIFF_VALUE DIFF_VALUE::FromString( const wxString& aValue )
149{
150 return FromString( std::string( aValue.ToUTF8() ) );
151}
152
153
154DIFF_VALUE DIFF_VALUE::FromString( const std::string& aValue )
155{
156 DIFF_VALUE v;
157 v.m_type = T::STRING;
158 v.m_value = aValue;
159 return v;
160}
161
162
164{
165 DIFF_VALUE v;
166 v.m_type = T::KIID;
167 v.m_value = aValue;
168 return v;
169}
170
171
173{
174 DIFF_VALUE v;
176 v.m_value = aValue;
177 return v;
178}
179
180
182{
183 DIFF_VALUE v;
184 v.m_type = T::BOX2I;
185 v.m_value = aValue;
186 return v;
187}
188
189
191{
192 DIFF_VALUE v;
193 v.m_type = T::COLOR;
194 v.m_value = aValue;
195 return v;
196}
197
198
200{
201 DIFF_VALUE v;
202 v.m_type = T::LAYER;
203 v.m_value = aLayer;
204 return v;
205}
206
207
208DIFF_VALUE DIFF_VALUE::FromEnum( int aValue, const std::string& aLabel )
209{
210 DIFF_VALUE v;
211 v.m_type = T::ENUM;
212 v.m_value = EnumValue{ aValue, aLabel };
213 return v;
214}
215
216
218{
219 DIFF_VALUE v;
221 v.m_value = std::move( aValue );
222 return v;
223}
224
225
227{
228 return std::get<bool>( m_value );
229}
230
231
233{
234 return std::get<int>( m_value );
235}
236
237
238int64_t DIFF_VALUE::AsInt64() const
239{
240 return std::get<int64_t>( m_value );
241}
242
243
245{
246 return std::get<double>( m_value );
247}
248
249
250wxString DIFF_VALUE::AsString() const
251{
252 return wxString::FromUTF8( std::get<std::string>( m_value ) );
253}
254
255
257{
258 return std::get<KIID>( m_value );
259}
260
261
263{
264 return std::get<VECTOR2I>( m_value );
265}
266
267
269{
270 return std::get<BOX2I>( m_value );
271}
272
273
275{
276 return std::get<KIGFX::COLOR4D>( m_value );
277}
278
279
281{
282 return std::get<PCB_LAYER_ID>( m_value );
283}
284
285
287{
288 return std::get<EnumValue>( m_value );
289}
290
291
293{
294 return std::get<PolygonSet>( m_value );
295}
296
297
299{
300 switch( m_type )
301 {
302 case T::NONE:
303 return wxS( "<none>" );
304
305 case T::BOOL:
306 return AsBool() ? wxS( "true" ) : wxS( "false" );
307
308 case T::INT:
309 return wxString::Format( wxS( "%d" ), AsInt() );
310
311 case T::INT64:
312 return wxString::Format( wxS( "%lld" ), static_cast<long long>( AsInt64() ) );
313
314 case T::DOUBLE:
315 return wxString::Format( wxS( "%g" ), AsDouble() );
316
317 case T::STRING:
318 return AsString();
319
320 case T::KIID:
321 return AsKiid().AsString();
322
323 case T::VECTOR2I:
324 {
325 VECTOR2I p = AsVector2I();
326 return wxString::Format( wxS( "(%d, %d)" ), p.x, p.y );
327 }
328
329 case T::BOX2I:
330 {
331 BOX2I b = AsBox2I();
332 return wxString::Format( wxS( "[(%d, %d) %dx%d]" ),
333 b.GetX(), b.GetY(), b.GetWidth(), b.GetHeight() );
334 }
335
336 case T::COLOR:
337 return AsColor().ToCSSString();
338
339 case T::LAYER:
340 return LayerName( AsLayer() );
341
342 case T::ENUM:
343 {
344 EnumValue ev = AsEnum();
345
346 if( !ev.second.empty() )
347 return wxString::FromUTF8( ev.second );
348
349 return wxString::Format( wxS( "%d" ), ev.first );
350 }
351
352 case T::POLYGON_SET:
353 {
354 const PolygonSet& ps = AsPolygonSet();
355 int outlineCount = 0;
356 int holeCount = 0;
357 int vertexCount = 0;
358
359 for( const auto& poly : ps )
360 {
361 if( !poly.empty() )
362 ++outlineCount;
363
364 if( poly.size() > 1 )
365 holeCount += static_cast<int>( poly.size() ) - 1;
366
367 for( const auto& contour : poly )
368 vertexCount += static_cast<int>( contour.size() );
369 }
370
371 return wxString::Format( wxS( "%d outline(s), %d hole(s), %d vertex(es)" ), outlineCount, holeCount,
372 vertexCount );
373 }
374 }
375
376 return wxEmptyString;
377}
378
379
380wxString DIFF_VALUE::ToDisplayString( EDA_UNITS aUnits, const EDA_IU_SCALE& aScale ) const
381{
383 return ToDisplayString();
384
385 switch( m_type )
386 {
387 case T::INT:
388 case T::INT64:
389 {
390 double value = ( m_type == T::INT ) ? static_cast<double>( AsInt() )
391 : static_cast<double>( AsInt64() );
392
395
396 return EDA_UNIT_UTILS::UI::StringFromValue( aScale, aUnits, value, true );
397 }
398
399 case T::DOUBLE:
400 {
401 double value = AsDouble();
402
405
406 return EDA_UNIT_UTILS::UI::StringFromValue( aScale, aUnits, value, true );
407 }
408
409 case T::VECTOR2I:
410 {
411 VECTOR2I p = AsVector2I();
412 wxString x = EDA_UNIT_UTILS::UI::StringFromValue( aScale, aUnits, p.x, true );
413 wxString y = EDA_UNIT_UTILS::UI::StringFromValue( aScale, aUnits, p.y, true );
414
415 return wxString::Format( wxS( "(%s, %s)" ), x, y );
416 }
417
418 default:
419 return ToDisplayString();
420 }
421}
422
423
424bool DIFF_VALUE::operator==( const DIFF_VALUE& aOther ) const
425{
426 return m_type == aOther.m_type && m_value == aOther.m_value;
427}
428
429
430nlohmann::json DIFF_VALUE::ToJson() const
431{
432 nlohmann::json j;
433 j["type"] = typeTag( m_type );
434
435 switch( m_type )
436 {
437 case T::NONE:
438 break;
439
440 case T::BOOL:
441 j["v"] = AsBool();
442 break;
443
444 case T::INT:
445 j["v"] = AsInt();
446 break;
447
448 case T::INT64:
449 j["v"] = AsInt64();
450 break;
451
452 case T::DOUBLE:
453 j["v"] = AsDouble();
454 break;
455
456 case T::STRING:
457 j["v"] = std::get<std::string>( m_value );
458 break;
459
460 case T::KIID:
461 j["v"] = AsKiid().AsStdString();
462 break;
463
464 case T::VECTOR2I:
465 {
466 VECTOR2I p = AsVector2I();
467 j["v"] = { p.x, p.y };
468 break;
469 }
470
471 case T::BOX2I:
472 {
473 BOX2I b = AsBox2I();
474 j["v"] = { b.GetX(), b.GetY(), b.GetWidth(), b.GetHeight() };
475 break;
476 }
477
478 case T::COLOR:
479 {
481 j["v"] = { c.r, c.g, c.b, c.a };
482 break;
483 }
484
485 case T::LAYER:
486 j["v"] = static_cast<int>( AsLayer() );
487 break;
488
489 case T::ENUM:
490 {
491 EnumValue ev = AsEnum();
492 j["v"] = ev.first;
493 j["label"] = ev.second;
494 break;
495 }
496
497 case T::POLYGON_SET:
498 {
499 const PolygonSet& ps = AsPolygonSet();
500 nlohmann::json polygons = nlohmann::json::array();
501
502 for( const auto& poly : ps )
503 {
504 nlohmann::json contours = nlohmann::json::array();
505
506 for( const auto& contour : poly )
507 {
508 nlohmann::json points = nlohmann::json::array();
509
510 for( const VECTOR2I& pt : contour )
511 points.push_back( { pt.x, pt.y } );
512
513 contours.push_back( std::move( points ) );
514 }
515
516 polygons.push_back( std::move( contours ) );
517 }
518
519 j["v"] = std::move( polygons );
520 break;
521 }
522 }
523
524 return j;
525}
526
527
528DIFF_VALUE DIFF_VALUE::FromJson( const nlohmann::json& aJson )
529{
530 // The display hint is not serialized, so every reconstructed value carries
531 // DISPLAY_HINT::NONE and renders in raw internal units under the unit-aware
532 // overload; only freshly-converted values get unit formatting.
533 if( !aJson.contains( "type" ) )
534 return DIFF_VALUE();
535
536 T type = typeFromTag( aJson.at( "type" ).get<std::string>() );
537
538 switch( type )
539 {
540 case T::NONE:
541 return DIFF_VALUE();
542
543 case T::BOOL:
544 return FromBool( aJson.at( "v" ).get<bool>() );
545
546 case T::INT:
547 return FromInt( aJson.at( "v" ).get<int>() );
548
549 case T::INT64:
550 return FromInt64( aJson.at( "v" ).get<int64_t>() );
551
552 case T::DOUBLE:
553 return FromDouble( aJson.at( "v" ).get<double>() );
554
555 case T::STRING:
556 return FromString( aJson.at( "v" ).get<std::string>() );
557
558 case T::KIID:
559 return FromKiid( KIID( aJson.at( "v" ).get<std::string>() ) );
560
561 case T::VECTOR2I:
562 {
563 const auto& arr = aJson.at( "v" );
564 return FromVector2I( VECTOR2I( arr.at( 0 ).get<int>(), arr.at( 1 ).get<int>() ) );
565 }
566
567 case T::BOX2I:
568 {
569 const auto& arr = aJson.at( "v" );
570 BOX2I b( VECTOR2I( arr.at( 0 ).get<int>(), arr.at( 1 ).get<int>() ),
571 VECTOR2I( arr.at( 2 ).get<int>(), arr.at( 3 ).get<int>() ) );
572 return FromBox2I( b );
573 }
574
575 case T::COLOR:
576 {
577 const auto& arr = aJson.at( "v" );
578 return FromColor( KIGFX::COLOR4D( arr.at( 0 ).get<double>(),
579 arr.at( 1 ).get<double>(),
580 arr.at( 2 ).get<double>(),
581 arr.at( 3 ).get<double>() ) );
582 }
583
584 case T::LAYER:
585 return FromLayer( static_cast<PCB_LAYER_ID>( aJson.at( "v" ).get<int>() ) );
586
587 case T::ENUM:
588 {
589 std::string label;
590
591 if( aJson.contains( "label" ) )
592 label = aJson.at( "label" ).get<std::string>();
593
594 return FromEnum( aJson.at( "v" ).get<int>(), label );
595 }
596
597 case T::POLYGON_SET:
598 {
599 PolygonSet ps;
600 const auto& polygons = aJson.at( "v" );
601
602 for( const auto& poly : polygons )
603 {
604 std::vector<std::vector<VECTOR2I>> contours;
605
606 for( const auto& contour : poly )
607 {
608 std::vector<VECTOR2I> points;
609
610 for( const auto& pt : contour )
611 points.emplace_back( pt.at( 0 ).get<int>(), pt.at( 1 ).get<int>() );
612
613 contours.push_back( std::move( points ) );
614 }
615
616 ps.push_back( std::move( contours ) );
617 }
618
619 return FromPolygonSet( std::move( ps ) );
620 }
621 }
622
623 return DIFF_VALUE();
624}
625
626
628{
629 return name == aOther.name && before == aOther.before && after == aOther.after;
630}
631
632
633nlohmann::json PROPERTY_DELTA::ToJson() const
634{
635 return { { "name", name },
636 { "before", before.ToJson() },
637 { "after", after.ToJson() } };
638}
639
640
641PROPERTY_DELTA PROPERTY_DELTA::FromJson( const nlohmann::json& aJson )
642{
644 d.name = aJson.at( "name" ).get<wxString>();
645 d.before = DIFF_VALUE::FromJson( aJson.at( "before" ) );
646 d.after = DIFF_VALUE::FromJson( aJson.at( "after" ) );
647 return d;
648}
649
650
651bool ITEM_CHANGE::operator==( const ITEM_CHANGE& aOther ) const
652{
653 return id == aOther.id
654 && typeName == aOther.typeName
655 && kind == aOther.kind
656 && properties == aOther.properties
657 && bbox == aOther.bbox
658 && refdes == aOther.refdes
659 && children == aOther.children;
660}
661
662
663nlohmann::json ITEM_CHANGE::ToJson() const
664{
665 nlohmann::json j;
666 j["id"] = id.AsString();
667 j["typeName"] = typeName;
668 j["kind"] = ChangeKindToString( kind );
669
670 nlohmann::json props = nlohmann::json::array();
671
672 for( const PROPERTY_DELTA& p : properties )
673 props.push_back( p.ToJson() );
674
675 j["properties"] = std::move( props );
676
677 j["bbox"] = { bbox.GetX(), bbox.GetY(), bbox.GetWidth(), bbox.GetHeight() };
678
679 if( refdes.has_value() )
680 j["refdes"] = *refdes;
681
682 nlohmann::json kids = nlohmann::json::array();
683
684 for( const ITEM_CHANGE& c : children )
685 kids.push_back( c.ToJson() );
686
687 j["children"] = std::move( kids );
688
689 return j;
690}
691
692
693ITEM_CHANGE ITEM_CHANGE::FromJson( const nlohmann::json& aJson )
694{
695 ITEM_CHANGE c;
696 c.id = KIID_PATH( aJson.at( "id" ).get<wxString>() );
697 c.typeName = aJson.at( "typeName" ).get<wxString>();
698 c.kind = ChangeKindFromString( aJson.at( "kind" ).get<std::string>() );
699
700 for( const auto& p : aJson.at( "properties" ) )
701 c.properties.push_back( PROPERTY_DELTA::FromJson( p ) );
702
703 const auto& b = aJson.at( "bbox" );
704 c.bbox = BOX2I( VECTOR2I( b.at( 0 ).get<int>(), b.at( 1 ).get<int>() ),
705 VECTOR2I( b.at( 2 ).get<int>(), b.at( 3 ).get<int>() ) );
706
707 if( aJson.contains( "refdes" ) )
708 c.refdes = aJson.at( "refdes" ).get<wxString>();
709
710 for( const auto& kid : aJson.at( "children" ) )
711 c.children.push_back( ITEM_CHANGE::FromJson( kid ) );
712
713 return c;
714}
715
716
717nlohmann::json DOCUMENT_DIFF::ToJson() const
718{
719 nlohmann::json j;
720 j["path"] = path;
721 j["docType"] = docType;
722
723 nlohmann::json arr = nlohmann::json::array();
724
725 for( const ITEM_CHANGE& c : changes )
726 arr.push_back( c.ToJson() );
727
728 j["changes"] = std::move( arr );
729 return j;
730}
731
732
733DOCUMENT_DIFF DOCUMENT_DIFF::FromJson( const nlohmann::json& aJson )
734{
736 d.path = aJson.at( "path" ).get<wxString>();
737 d.docType = aJson.at( "docType" ).get<wxString>();
738
739 for( const auto& c : aJson.at( "changes" ) )
740 d.changes.push_back( ITEM_CHANGE::FromJson( c ) );
741
742 return d;
743}
744
745
747{
748 for( const DOCUMENT_DIFF& d : documents )
749 {
750 if( !d.Empty() )
751 return false;
752 }
753
754 return true;
755}
756
757
758nlohmann::json PROJECT_DIFF::ToJson() const
759{
760 nlohmann::json arr = nlohmann::json::array();
761
762 for( const DOCUMENT_DIFF& d : documents )
763 arr.push_back( d.ToJson() );
764
765 return { { "documents", std::move( arr ) } };
766}
767
768
769PROJECT_DIFF PROJECT_DIFF::FromJson( const nlohmann::json& aJson )
770{
771 PROJECT_DIFF p;
772
773 for( const auto& d : aJson.at( "documents" ) )
774 p.documents.push_back( DOCUMENT_DIFF::FromJson( d ) );
775
776 return p;
777}
778
779
780const char* ChangeKindToString( CHANGE_KIND aKind )
781{
782 switch( aKind )
783 {
784 case CHANGE_KIND::ADDED: return "added";
785 case CHANGE_KIND::REMOVED: return "removed";
786 case CHANGE_KIND::MODIFIED: return "modified";
787 case CHANGE_KIND::COLLISION: return "collision";
788 case CHANGE_KIND::DUPLICATE_UUID: return "duplicate_uuid";
789 }
790
791 return "unknown";
792}
793
794
795CHANGE_KIND ChangeKindFromString( const std::string& aKind )
796{
797 if( aKind == "added" ) return CHANGE_KIND::ADDED;
798 if( aKind == "removed" ) return CHANGE_KIND::REMOVED;
799 if( aKind == "modified" ) return CHANGE_KIND::MODIFIED;
800 if( aKind == "collision" ) return CHANGE_KIND::COLLISION;
801 if( aKind == "duplicate_uuid" ) return CHANGE_KIND::DUPLICATE_UUID;
802
803 throw std::invalid_argument( "Unknown CHANGE_KIND tag: " + aKind );
804}
805
806
807std::string FormatDiffAsText( const DOCUMENT_DIFF& aDiff, const wxString& aLabelA,
808 const wxString& aLabelB, EDA_UNITS aUnits,
809 const EDA_IU_SCALE& aScale )
810{
811 std::ostringstream ss;
812 ss << "diff " << aLabelA.ToStdString() << " " << aLabelB.ToStdString() << "\n";
813 ss << aDiff.changes.size() << " change(s)\n";
814
815 std::function<void( const ITEM_CHANGE&, int )> writeChange;
816
817 writeChange = [&]( const ITEM_CHANGE& aChange, int aDepth )
818 {
819 std::string indent( static_cast<std::size_t>( 2 + aDepth * 2 ), ' ' );
820
821 ss << indent << ChangeKindToString( aChange.kind ) << " " << aChange.typeName.ToStdString()
822 << " " << aChange.id.AsString().ToStdString();
823
824 if( aChange.refdes.has_value() )
825 ss << " [" << aChange.refdes->ToStdString() << "]";
826
827 ss << "\n";
828
829 std::string propIndent( static_cast<std::size_t>( 4 + aDepth * 2 ), ' ' );
830
831 for( const PROPERTY_DELTA& p : aChange.properties )
832 {
833 ss << propIndent << p.name.ToStdString() << ": "
834 << p.before.ToDisplayString( aUnits, aScale ).ToStdString() << " -> "
835 << p.after.ToDisplayString( aUnits, aScale ).ToStdString() << "\n";
836 }
837
838 for( const ITEM_CHANGE& child : aChange.children )
839 writeChange( child, aDepth + 1 );
840 };
841
842 for( const ITEM_CHANGE& c : aDiff.changes )
843 writeChange( c, 0 );
844
845 return ss.str();
846}
847
848
849bool WriteDiffOutput( const std::string& aContent, const wxString& aOutputPath )
850{
851 if( aOutputPath.IsEmpty() )
852 {
853 return fwrite( aContent.data(), 1, aContent.size(), stdout ) == aContent.size()
854 && ferror( stdout ) == 0;
855 }
856
857 wxFile out( aOutputPath, wxFile::write );
858
859 if( !out.IsOpened() )
860 return false;
861
862 out.Write( aContent.data(), aContent.size() );
863 return true;
864}
865
866} // namespace KICAD_DIFF
BOX2< VECTOR2I > BOX2I
Definition box2.h:918
constexpr coord_type GetY() const
Definition box2.h:204
constexpr size_type GetWidth() const
Definition box2.h:210
constexpr coord_type GetX() const
Definition box2.h:203
constexpr size_type GetHeight() const
Definition box2.h:211
static DIFF_VALUE FromLayer(PCB_LAYER_ID aLayer)
static DIFF_VALUE FromDouble(double aValue)
static DIFF_VALUE FromEnum(int aValue, const std::string &aLabel)
KIGFX::COLOR4D AsColor() const
static DIFF_VALUE FromInt64(int64_t aValue)
static DIFF_VALUE FromInt(int aValue)
static DIFF_VALUE FromBox2I(const BOX2I &aValue)
const PolygonSet & AsPolygonSet() const
bool operator==(const DIFF_VALUE &aOther) const
std::pair< int, std::string > EnumValue
Enum payload: (numeric_value, label) so JSON output is human-readable while the integer is the canoni...
static DIFF_VALUE FromKiid(const KIID &aValue)
static DIFF_VALUE FromColor(const KIGFX::COLOR4D &aValue)
wxString ToDisplayString() const
Human-readable representation with no unit context.
nlohmann::json ToJson() const
static DIFF_VALUE FromBool(bool aValue)
static DIFF_VALUE FromString(const wxString &aValue)
std::vector< std::vector< std::vector< VECTOR2I > > > PolygonSet
static DIFF_VALUE FromJson(const nlohmann::json &aJson)
DISPLAY_HINT m_displayHint
Presentation aid only; excluded from operator== and JSON (see DISPLAY_HINT).
static DIFF_VALUE FromPolygonSet(PolygonSet aValue)
PCB_LAYER_ID AsLayer() const
static DIFF_VALUE FromVector2I(const VECTOR2I &aValue)
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:101
double r
Red component.
Definition color4d.h:389
double g
Green component.
Definition color4d.h:390
double a
Alpha component.
Definition color4d.h:392
double b
Blue component.
Definition color4d.h:391
wxString AsString() const
Definition kiid.cpp:393
@ DEGREES_T
Definition eda_angle.h:31
EDA_UNITS
Definition eda_units.h:44
#define KICOMMON_API
Definition kicommon.h:27
wxString LayerName(int aLayer)
Returns the default display name for a given layer.
Definition layer_id.cpp:31
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
KICOMMON_API wxString MessageTextFromValue(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, double aValue, bool aAddUnitsText=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
A helper to convert the double length aValue to a string in inches, millimeters, or unscaled units.
KICOMMON_API wxString StringFromValue(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, double aValue, bool aAddUnitsText=false, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Return the string from aValue according to aUnits (inch, mm ...) for display.
CHANGE_KIND
Coarse classification of a single item-level change between two documents.
CHANGE_KIND ChangeKindFromString(const std::string &aKind)
bool WriteDiffOutput(const std::string &aContent, const wxString &aOutputPath)
Write diff/merge text output to aOutputPath, or to stdout when the path is empty.
@ ANGLE
Angle in degrees (PT_DEGREE)
const char * ChangeKindToString(CHANGE_KIND aKind)
std::string FormatDiffAsText(const DOCUMENT_DIFF &aDiff, const wxString &aLabelA, const wxString &aLabelB, EDA_UNITS aUnits, const EDA_IU_SCALE &aScale)
Render a DOCUMENT_DIFF as the human-readable text report shared by the diff jobs and CLI: a diff <lab...
The full set of changes between two parsed documents of one type.
nlohmann::json ToJson() const
static DOCUMENT_DIFF FromJson(const nlohmann::json &aJson)
std::vector< ITEM_CHANGE > changes
One change record on a single item.
static ITEM_CHANGE FromJson(const nlohmann::json &aJson)
bool operator==(const ITEM_CHANGE &aOther) const
std::vector< PROPERTY_DELTA > properties
std::optional< wxString > refdes
std::vector< ITEM_CHANGE > children
nlohmann::json ToJson() const
Aggregated project-level diff covering many documents.
nlohmann::json ToJson() const
std::vector< DOCUMENT_DIFF > documents
static PROJECT_DIFF FromJson(const nlohmann::json &aJson)
Single (name, before, after) triple for one mutated property on an item.
static PROPERTY_DELTA FromJson(const nlohmann::json &aJson)
nlohmann::json ToJson() const
bool operator==(const PROPERTY_DELTA &aOther) const
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683