KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_schematic_clipboard_export.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 modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
29
30#include <boost/test/unit_test.hpp>
31
32#include <sch_symbol.h>
33#include <sch_line.h>
34#include <sch_junction.h>
35#include <sch_bus_entry.h>
36#include <sch_no_connect.h>
37#include <sch_text.h>
38#include <sch_label.h>
39#include <sch_shape.h>
40#include <sch_sheet.h>
41#include <lib_symbol.h>
43#include <sch_painter.h>
44#include <sch_plotter.h>
45#include <locale_io.h>
47#include <wx/ffile.h>
48#include <wx/mstream.h>
49
50
52{
53public:
56
57 std::unique_ptr<SCH_LINE> CreateWire( int x1, int y1, int x2, int y2 )
58 {
59 auto wire = std::make_unique<SCH_LINE>(
60 VECTOR2I( schIUScale.MilsToIU( x1 ), schIUScale.MilsToIU( y1 ) ),
61 LAYER_WIRE );
62 wire->SetEndPoint( VECTOR2I( schIUScale.MilsToIU( x2 ), schIUScale.MilsToIU( y2 ) ) );
63 m_items.push_back( wire.get() );
64 return wire;
65 }
66
67 std::unique_ptr<SCH_LINE> CreateBus( int x1, int y1, int x2, int y2 )
68 {
69 auto bus = std::make_unique<SCH_LINE>(
70 VECTOR2I( schIUScale.MilsToIU( x1 ), schIUScale.MilsToIU( y1 ) ),
71 LAYER_BUS );
72 bus->SetEndPoint( VECTOR2I( schIUScale.MilsToIU( x2 ), schIUScale.MilsToIU( y2 ) ) );
73 m_items.push_back( bus.get() );
74 return bus;
75 }
76
77 std::unique_ptr<SCH_JUNCTION> CreateJunction( int x, int y )
78 {
79 auto junction = std::make_unique<SCH_JUNCTION>(
80 VECTOR2I( schIUScale.MilsToIU( x ), schIUScale.MilsToIU( y ) ) );
81 m_items.push_back( junction.get() );
82 return junction;
83 }
84
85 std::unique_ptr<SCH_NO_CONNECT> CreateNoConnect( int x, int y )
86 {
87 auto noConnect = std::make_unique<SCH_NO_CONNECT>(
88 VECTOR2I( schIUScale.MilsToIU( x ), schIUScale.MilsToIU( y ) ) );
89 m_items.push_back( noConnect.get() );
90 return noConnect;
91 }
92
93 std::unique_ptr<SCH_BUS_WIRE_ENTRY> CreateBusEntry( int x, int y )
94 {
95 auto entry = std::make_unique<SCH_BUS_WIRE_ENTRY>(
96 VECTOR2I( schIUScale.MilsToIU( x ), schIUScale.MilsToIU( y ) ) );
97 m_items.push_back( entry.get() );
98 return entry;
99 }
100
101 std::unique_ptr<SCH_TEXT> CreateText( int x, int y, const wxString& text )
102 {
103 auto schText = std::make_unique<SCH_TEXT>(
104 VECTOR2I( schIUScale.MilsToIU( x ), schIUScale.MilsToIU( y ) ), text );
105 schText->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 50 ), schIUScale.MilsToIU( 50 ) ) );
106 m_items.push_back( schText.get() );
107 return schText;
108 }
109
110 std::unique_ptr<SCH_LABEL> CreateLabel( int x, int y, const wxString& text )
111 {
112 auto label = std::make_unique<SCH_LABEL>(
113 VECTOR2I( schIUScale.MilsToIU( x ), schIUScale.MilsToIU( y ) ), text );
114 m_items.push_back( label.get() );
115 return label;
116 }
117
118 std::unique_ptr<SCH_GLOBALLABEL> CreateGlobalLabel( int x, int y, const wxString& text )
119 {
120 auto label = std::make_unique<SCH_GLOBALLABEL>(
121 VECTOR2I( schIUScale.MilsToIU( x ), schIUScale.MilsToIU( y ) ), text );
122 m_items.push_back( label.get() );
123 return label;
124 }
125
126 std::unique_ptr<SCH_HIERLABEL> CreateHierLabel( int x, int y, const wxString& text )
127 {
128 auto label = std::make_unique<SCH_HIERLABEL>(
129 VECTOR2I( schIUScale.MilsToIU( x ), schIUScale.MilsToIU( y ) ), text );
130 m_items.push_back( label.get() );
131 return label;
132 }
133
134 std::unique_ptr<SCH_SHAPE> CreateRectangle( int x1, int y1, int x2, int y2 )
135 {
136 auto rect = std::make_unique<SCH_SHAPE>( SHAPE_T::RECTANGLE );
137 rect->SetPosition( VECTOR2I( schIUScale.MilsToIU( x1 ), schIUScale.MilsToIU( y1 ) ) );
138 rect->SetEnd( VECTOR2I( schIUScale.MilsToIU( x2 ), schIUScale.MilsToIU( y2 ) ) );
139 rect->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), LINE_STYLE::SOLID ) );
140 m_items.push_back( rect.get() );
141 return rect;
142 }
143
144 std::unique_ptr<SCH_SHAPE> CreateCircle( int cx, int cy, int radius )
145 {
146 auto circle = std::make_unique<SCH_SHAPE>( SHAPE_T::CIRCLE );
147 circle->SetPosition( VECTOR2I( schIUScale.MilsToIU( cx ), schIUScale.MilsToIU( cy ) ) );
148 circle->SetEnd( VECTOR2I( schIUScale.MilsToIU( cx + radius ), schIUScale.MilsToIU( cy ) ) );
149 circle->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), LINE_STYLE::SOLID ) );
150 m_items.push_back( circle.get() );
151 return circle;
152 }
153
154 std::unique_ptr<SCH_SHAPE> CreatePolyline( const std::vector<std::pair<int, int>>& points )
155 {
156 auto poly = std::make_unique<SCH_SHAPE>( SHAPE_T::POLY );
157 poly->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), LINE_STYLE::SOLID ) );
158
159 for( const auto& pt : points )
160 poly->AddPoint( VECTOR2I( schIUScale.MilsToIU( pt.first ), schIUScale.MilsToIU( pt.second ) ) );
161
162 m_items.push_back( poly.get() );
163 return poly;
164 }
165
167 {
168 m_items.clear();
169 }
170
171 std::vector<SCH_ITEM*> m_items;
172};
173
174
175BOOST_FIXTURE_TEST_SUITE( SchematicClipboardExport, SCHEMATIC_CLIPBOARD_FIXTURE )
176
177
178
181BOOST_AUTO_TEST_CASE( ElementCreation_Wires )
182{
183 auto wire = CreateWire( 0, 0, 100, 0 );
184
185 BOOST_CHECK( wire != nullptr );
186 BOOST_CHECK( wire->IsWire() );
187 BOOST_CHECK_EQUAL( wire->GetStartPoint().x, schIUScale.MilsToIU( 0 ) );
188 BOOST_CHECK_EQUAL( wire->GetEndPoint().x, schIUScale.MilsToIU( 100 ) );
189}
190
191
195BOOST_AUTO_TEST_CASE( ElementCreation_Buses )
196{
197 auto bus = CreateBus( 0, 0, 0, 100 );
198
199 BOOST_CHECK( bus != nullptr );
200 BOOST_CHECK( bus->IsBus() );
201}
202
203
207BOOST_AUTO_TEST_CASE( ElementCreation_Junctions )
208{
209 auto junction = CreateJunction( 50, 50 );
210
211 BOOST_CHECK( junction != nullptr );
212 BOOST_CHECK_EQUAL( junction->GetPosition().x, schIUScale.MilsToIU( 50 ) );
213 BOOST_CHECK_EQUAL( junction->GetPosition().y, schIUScale.MilsToIU( 50 ) );
214}
215
216
220BOOST_AUTO_TEST_CASE( ElementCreation_NoConnect )
221{
222 auto noConnect = CreateNoConnect( 100, 100 );
223
224 BOOST_CHECK( noConnect != nullptr );
225 BOOST_CHECK( noConnect->Type() == SCH_NO_CONNECT_T );
226}
227
228
232BOOST_AUTO_TEST_CASE( ElementCreation_BusEntry )
233{
234 auto entry = CreateBusEntry( 150, 150 );
235
236 BOOST_CHECK( entry != nullptr );
237 BOOST_CHECK( entry->Type() == SCH_BUS_WIRE_ENTRY_T );
238}
239
240
244BOOST_AUTO_TEST_CASE( ElementCreation_Text )
245{
246 auto text = CreateText( 200, 200, wxT( "Test Text" ) );
247
248 BOOST_CHECK( text != nullptr );
249 BOOST_CHECK( text->GetText() == wxT( "Test Text" ) );
250}
251
252
256BOOST_AUTO_TEST_CASE( ElementCreation_Labels )
257{
258 auto label = CreateLabel( 0, 0, wxT( "NET1" ) );
259 auto globalLabel = CreateGlobalLabel( 100, 0, wxT( "VCC" ) );
260 auto hierLabel = CreateHierLabel( 200, 0, wxT( "DATA_IN" ) );
261
262 BOOST_CHECK( label != nullptr );
263 BOOST_CHECK( globalLabel != nullptr );
264 BOOST_CHECK( hierLabel != nullptr );
265
266 BOOST_CHECK( label->Type() == SCH_LABEL_T );
267 BOOST_CHECK( globalLabel->Type() == SCH_GLOBAL_LABEL_T );
268 BOOST_CHECK( hierLabel->Type() == SCH_HIER_LABEL_T );
269}
270
271
275BOOST_AUTO_TEST_CASE( ElementCreation_Shapes )
276{
277 auto rect = CreateRectangle( 0, 0, 100, 100 );
278 auto circle = CreateCircle( 200, 50, 50 );
279 auto poly = CreatePolyline( { { 300, 0 }, { 350, 50 }, { 300, 100 } } );
280
281 BOOST_CHECK( rect != nullptr );
282 BOOST_CHECK( circle != nullptr );
283 BOOST_CHECK( poly != nullptr );
284
285 BOOST_CHECK( rect->GetShape() == SHAPE_T::RECTANGLE );
286 BOOST_CHECK( circle->GetShape() == SHAPE_T::CIRCLE );
287 BOOST_CHECK( poly->GetShape() == SHAPE_T::POLY );
288}
289
290
294BOOST_AUTO_TEST_CASE( Wire_Endpoints )
295{
296 auto wire1 = CreateWire( 0, 0, 100, 0 );
297 auto wire2 = CreateWire( 0, 0, 0, 100 );
298
299 // Verify wire endpoints
300 BOOST_CHECK_EQUAL( wire1->GetStartPoint().x, schIUScale.MilsToIU( 0 ) );
301 BOOST_CHECK_EQUAL( wire1->GetEndPoint().x, schIUScale.MilsToIU( 100 ) );
302 BOOST_CHECK_EQUAL( wire2->GetStartPoint().y, schIUScale.MilsToIU( 0 ) );
303 BOOST_CHECK_EQUAL( wire2->GetEndPoint().y, schIUScale.MilsToIU( 100 ) );
304}
305
306
310BOOST_AUTO_TEST_CASE( MixedElements_Positions )
311{
312 auto wire = CreateWire( 0, 0, 100, 0 );
313 auto junction = CreateJunction( 100, 0 );
314 auto text = CreateText( 150, 0, wxT( "Label" ) );
315
316 // Verify positions
317 BOOST_CHECK_EQUAL( wire->GetEndPoint().x, schIUScale.MilsToIU( 100 ) );
318 BOOST_CHECK_EQUAL( junction->GetPosition().x, schIUScale.MilsToIU( 100 ) );
319 BOOST_CHECK_EQUAL( text->GetPosition().x, schIUScale.MilsToIU( 150 ) );
320}
321
322
326BOOST_AUTO_TEST_CASE( Rectangle_Dimensions )
327{
328 auto rect = CreateRectangle( -50, -50, 50, 50 );
329
330 // Verify the rectangle was created with correct points
331 BOOST_CHECK_EQUAL( rect->GetStart().x, schIUScale.MilsToIU( -50 ) );
332 BOOST_CHECK_EQUAL( rect->GetStart().y, schIUScale.MilsToIU( -50 ) );
333 BOOST_CHECK_EQUAL( rect->GetEnd().x, schIUScale.MilsToIU( 50 ) );
334 BOOST_CHECK_EQUAL( rect->GetEnd().y, schIUScale.MilsToIU( 50 ) );
335}
336
337
341BOOST_AUTO_TEST_CASE( Circle_Creation )
342{
343 int radius = 100;
344 auto circle = CreateCircle( 0, 0, radius );
345
346 // Verify circle center and end point (which determines radius)
347 BOOST_CHECK_EQUAL( circle->GetStart().x, schIUScale.MilsToIU( 0 ) );
348 BOOST_CHECK_EQUAL( circle->GetStart().y, schIUScale.MilsToIU( 0 ) );
349 BOOST_CHECK_EQUAL( circle->GetEnd().x, schIUScale.MilsToIU( radius ) );
350}
351
352
356BOOST_AUTO_TEST_CASE( PngExport_AlphaComputation_Opaque )
357{
358 // Opaque pixel: same on white and black
359 int rW = 128, gW = 128, bW = 128;
360 int rB = 128, gB = 128, bB = 128;
361
362 int diffR = rW - rB;
363 int diffG = gW - gB;
364 int diffB = bW - bB;
365 int avgDiff = ( diffR + diffG + diffB ) / 3;
366 int alpha = 255 - avgDiff;
367
368 BOOST_CHECK_EQUAL( alpha, 255 );
369}
370
371
375BOOST_AUTO_TEST_CASE( PngExport_AlphaComputation_Transparent )
376{
377 // Transparent pixel: shows background
378 int rW = 255, gW = 255, bW = 255;
379 int rB = 0, gB = 0, bB = 0;
380
381 int diffR = rW - rB;
382 int diffG = gW - gB;
383 int diffB = bW - bB;
384 int avgDiff = ( diffR + diffG + diffB ) / 3;
385 int alpha = 255 - avgDiff;
386
387 BOOST_CHECK_EQUAL( alpha, 0 );
388}
389
390
394BOOST_AUTO_TEST_CASE( ComplexSchematic_MultipleLayers )
395{
396 // Create a simple schematic structure
397 // Wires
398 auto wire1 = CreateWire( 0, 0, 200, 0 );
399 auto wire2 = CreateWire( 200, 0, 200, 100 );
400
401 // Junction at intersection
402 auto junction = CreateJunction( 200, 0 );
403
404 // Bus and bus entry
405 auto bus = CreateBus( 0, 200, 300, 200 );
406 auto busEntry = CreateBusEntry( 150, 200 );
407
408 // Labels
409 auto label = CreateLabel( 50, -20, wxT( "NET_A" ) );
410 auto globalLabel = CreateGlobalLabel( 250, 50, wxT( "VCC" ) );
411
412 // Text
413 auto text = CreateText( 100, 300, wxT( "Note: Power section" ) );
414
415 // Shapes
416 auto rect = CreateRectangle( -50, -50, 350, 350 );
417
418 // Verify all items were created with correct types
419 BOOST_CHECK_EQUAL( m_items.size(), 9 );
420 BOOST_CHECK( wire1->IsWire() );
421 BOOST_CHECK( wire2->IsWire() );
422 BOOST_CHECK( bus->IsBus() );
423 BOOST_CHECK( junction->Type() == SCH_JUNCTION_T );
424 BOOST_CHECK( busEntry->Type() == SCH_BUS_WIRE_ENTRY_T );
425 BOOST_CHECK( label->Type() == SCH_LABEL_T );
426 BOOST_CHECK( globalLabel->Type() == SCH_GLOBAL_LABEL_T );
427 BOOST_CHECK( text->Type() == SCH_TEXT_T );
428 BOOST_CHECK( rect->GetShape() == SHAPE_T::RECTANGLE );
429}
430
431
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:114
std::unique_ptr< SCH_SHAPE > CreateRectangle(int x1, int y1, int x2, int y2)
std::unique_ptr< SCH_LINE > CreateBus(int x1, int y1, int x2, int y2)
~SCHEMATIC_CLIPBOARD_FIXTURE()=default
std::unique_ptr< SCH_BUS_WIRE_ENTRY > CreateBusEntry(int x, int y)
std::unique_ptr< SCH_LINE > CreateWire(int x1, int y1, int x2, int y2)
std::unique_ptr< SCH_GLOBALLABEL > CreateGlobalLabel(int x, int y, const wxString &text)
std::unique_ptr< SCH_JUNCTION > CreateJunction(int x, int y)
std::unique_ptr< SCH_LABEL > CreateLabel(int x, int y, const wxString &text)
std::unique_ptr< SCH_SHAPE > CreatePolyline(const std::vector< std::pair< int, int > > &points)
std::unique_ptr< SCH_SHAPE > CreateCircle(int cx, int cy, int radius)
std::unique_ptr< SCH_HIERLABEL > CreateHierLabel(int x, int y, const wxString &text)
std::unique_ptr< SCH_NO_CONNECT > CreateNoConnect(int x, int y)
std::unique_ptr< SCH_TEXT > CreateText(int x, int y, const wxString &text)
Simple container to manage line stroke parameters.
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
Definition eda_shape.h:46
@ LAYER_WIRE
Definition layer_ids.h:452
@ LAYER_BUS
Definition layer_ids.h:453
Plotting engines similar to ps (PostScript, Gerber, svg)
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_CASE(ElementCreation_Wires)
Test that wires can be created for export testing.
int radius
SHAPE_CIRCLE circle(c.m_circle_center, c.m_circle_radius)
BOOST_CHECK_EQUAL(result, "25.4")
@ SCH_NO_CONNECT_T
Definition typeinfo.h:164
@ SCH_LABEL_T
Definition typeinfo.h:171
@ SCH_HIER_LABEL_T
Definition typeinfo.h:173
@ SCH_TEXT_T
Definition typeinfo.h:155
@ SCH_BUS_WIRE_ENTRY_T
Definition typeinfo.h:165
@ SCH_GLOBAL_LABEL_T
Definition typeinfo.h:172
@ SCH_JUNCTION_T
Definition typeinfo.h:163
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695