KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_step_model_color_transfer.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 2
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, see <https://www.gnu.org/licenses/>.
18 */
19
20/*
21 * Regression test for https://gitlab.com/kicad/code/kicad/-/issues/24026
22 *
23 * Some default KiCad STEP models (e.g. SOT-89-3, TO-252-2, TO-263-2, TO-263-5_TabPin6)
24 * lost their colors when exported to STEP or 3D PDF because the XDE label tree was
25 * transferred via TDocStd_XLinkTool::Copy, which only copies a single label closure.
26 * These models store their colored "_part" labels as siblings of the assembly root
27 * (under the "Shapes" folder) rather than as descendants, so the closure did not
28 * include them and the downstream color-transfer pass found no matching shape.
29 *
30 * The fix routes transferModel() through XCAFDoc_Editor::Extract(), which rebuilds
31 * the XDE label tree by walking the component reference graph and automatically
32 * clones color/name metadata along with the shapes.
33 */
34
35#include <filesystem>
36#include <fstream>
37#include <sstream>
38
40#include <boost/test/unit_test.hpp>
41
43#include <reporter.h>
46#include <layer_ids.h>
47#include <footprint.h>
48
50
51#include <wx/filename.h>
52
53
54namespace
55{
56
57// Count occurrences of a substring in a text file. Used to verify that colors
58// survived the round trip into the exported STEP file.
59static int countEntities( const std::filesystem::path& aFile, const std::string& aToken )
60{
61 std::ifstream in( aFile );
62 BOOST_REQUIRE_MESSAGE( in.good(), "Cannot open exported STEP file for inspection" );
63
64 std::stringstream buf;
65 buf << in.rdbuf();
66 const std::string contents = buf.str();
67
68 int count = 0;
69 size_t pos = 0;
70
71 while( ( pos = contents.find( aToken, pos ) ) != std::string::npos )
72 {
73 ++count;
74 pos += aToken.size();
75 }
76
77 return count;
78}
79
80} // namespace
81
82
83BOOST_AUTO_TEST_SUITE( StepModelColorTransfer )
84
85
86
94BOOST_AUTO_TEST_CASE( TO252_2_ColorsPreserved )
95{
96 const std::filesystem::path sourceModel =
97 std::filesystem::path( KI_TEST::GetPcbnewTestDataDir() )
98 / "step_model_colors" / "TO-252-2.step";
99
100 BOOST_REQUIRE_MESSAGE( std::filesystem::exists( sourceModel ),
101 "Missing test model " << sourceModel.string() );
102
103 const std::filesystem::path outputFile =
104 std::filesystem::temp_directory_path() / "kicad_step_model_color_test.step";
105
106 if( std::filesystem::exists( outputFile ) )
107 std::filesystem::remove( outputFile );
108
110
111 STEP_PCB_MODEL model( wxT( "test" ), &reporter );
112 model.SpecializeVariant( OUTPUT_FORMAT::FMT_OUT_STEP );
113 model.SetCopperColor( 0.75, 0.61, 0.23 );
114 model.SetPadColor( 0.9, 0.9, 0.9 );
115
116 // Emit a trivial board outline so CreatePCB has something to extrude.
117 SHAPE_POLY_SET outline;
118 outline.NewOutline();
119 outline.Append( VECTOR2I( 0, 0 ) );
120 outline.Append( VECTOR2I( 10'000'000, 0 ) );
121 outline.Append( VECTOR2I( 10'000'000, 10'000'000 ) );
122 outline.Append( VECTOR2I( 0, 10'000'000 ) );
123
124 BOOST_REQUIRE( model.CreatePCB( outline, VECTOR2D( 0, 0 ), true ) );
125
126 const wxString modelPath = wxString::FromUTF8( sourceModel.string().c_str() );
127
128 const bool added = model.AddComponent( wxT( "TO-252-2" ), modelPath, {}, wxT( "U1" ), false,
129 VECTOR2D( 5.0, 5.0 ), 0.0, VECTOR3D( 0.0, 0.0, 0.0 ),
130 VECTOR3D( 0.0, 0.0, 0.0 ), VECTOR3D( 1.0, 1.0, 1.0 ),
131 false );
132
133 BOOST_REQUIRE_MESSAGE( added, "AddComponent failed for TO-252-2.step" );
134
135 const wxString outputPath = wxString::FromUTF8( outputFile.string().c_str() );
136
137 BOOST_REQUIRE_MESSAGE( model.WriteSTEP( outputPath, false, false ),
138 "WriteSTEP returned failure" );
139
140 BOOST_REQUIRE( std::filesystem::exists( outputFile ) );
141
142 const int styled = countEntities( outputFile, "STYLED_ITEM" );
143 const int colors = countEntities( outputFile, "COLOUR_RGB" );
144
145 BOOST_TEST_MESSAGE( "Exported STEP: " << styled << " STYLED_ITEM, " << colors
146 << " COLOUR_RGB entities" );
147
148 // The component model carries two distinct colors; the board body adds more. A healthy
149 // export must retain at least the component's colors (> 2 COLOUR_RGB); without the fix
150 // the component contribution is zero so COLOUR_RGB drops to whatever the board body emits.
152 styled > 0,
153 "Exported STEP has no STYLED_ITEM entities; component colors were dropped" );
155 colors > 2,
156 "Expected > 2 COLOUR_RGB entities (component + board); got " << colors
157 << ". Component model colors were not transferred." );
158
159 // Keep the file around for inspection when the test fails.
160 if( styled > 0 && colors > 2 && std::filesystem::exists( outputFile ) )
161 std::filesystem::remove( outputFile );
162}
163
164
General utilities for PCB file IO for QA programs.
A singleton reporter that reports to nowhere.
Definition reporter.h:214
Represent a set of closed polygons.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
int NewOutline()
Creates a new empty polygon in the set and returns its index.
std::string GetPcbnewTestDataDir()
Utility which returns a path to the data directory where the test board files are stored.
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
IbisParser parser & reporter
KIBIS_MODEL * model
BOOST_CHECK_MESSAGE(totalMismatches==0, std::to_string(totalMismatches)+" board(s) with strategy disagreements")
BOOST_TEST_MESSAGE("\n=== Real-World Polygon PIP Benchmark ===\n"<< formatTable(table))
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
VECTOR2< double > VECTOR2D
Definition vector2d.h:682
VECTOR3< double > VECTOR3D
Definition vector3.h:230