KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_ellipse_roundtrip.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
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20#include <qa_utils/file_utils.h>
22
23#include <board.h>
24#include <footprint.h>
25#include <pcb_shape.h>
26#include <geometry/eda_angle.h>
27#include <stroke_params.h>
28
30
31#include <filesystem>
32#include <memory>
33
34
35BOOST_AUTO_TEST_SUITE( EllipseRoundTrip )
36
37
38BOOST_AUTO_TEST_CASE( ClosedEllipseRoundTrip )
39{
40 // Build a minimal board in memory with a single closed ellipse.
41 auto board = std::make_unique<BOARD>();
42 auto shape = std::make_unique<PCB_SHAPE>( board.get() );
43 shape->SetShape( SHAPE_T::ELLIPSE );
44 shape->SetEllipseCenter( VECTOR2I( 100000, 200000 ) ); // 100 mm, 200 mm
45 shape->SetEllipseMajorRadius( 50000 ); // 50 mm
46 shape->SetEllipseMinorRadius( 30000 ); // 30 mm
47 shape->SetEllipseRotation( EDA_ANGLE( 30.0, DEGREES_T ) );
48 shape->SetLayer( F_SilkS );
49 shape->SetWidth( 150 ); // 0.15 mm
50 board->Add( shape.release(), ADD_MODE::APPEND, true );
51
52 // Save to a temp file.
53 KI_TEST::SCOPED_TEMP_DIR tmp( "kicad_qa_ellipse_roundtrip_closed" );
54 std::filesystem::path boardFile = tmp.Path() / "board.kicad_pcb";
55
56 KI_TEST::DumpBoardToFile( *board, boardFile.string() );
57
58 // Reload the file.
59 std::unique_ptr<BOARD> reloaded = KI_TEST::ReadBoardFromFileOrStream( boardFile.string() );
60 BOOST_REQUIRE( reloaded );
61
62 // Find the ellipse in the reloaded board and verify parameters.
63 PCB_SHAPE* found = nullptr;
64
65 for( BOARD_ITEM* item : reloaded->Drawings() )
66 {
67 if( PCB_SHAPE* ps = dynamic_cast<PCB_SHAPE*>( item ) )
68 {
69 if( ps->GetShape() == SHAPE_T::ELLIPSE )
70 {
71 found = ps;
72 break;
73 }
74 }
75 }
76
77 BOOST_REQUIRE_MESSAGE( found, "Ellipse not found in reloaded board" );
78
79 BOOST_CHECK_EQUAL( found->GetEllipseCenter().x, 100000 );
80 BOOST_CHECK_EQUAL( found->GetEllipseCenter().y, 200000 );
83 BOOST_CHECK_CLOSE( found->GetEllipseRotation().AsDegrees(), 30.0, 1e-6 );
84}
85
86
87BOOST_AUTO_TEST_CASE( EllipseArcRoundTrip )
88{
89 // Same as above but with elliptical arc.
90 auto board = std::make_unique<BOARD>();
91 auto shape = std::make_unique<PCB_SHAPE>( board.get() );
92 shape->SetShape( SHAPE_T::ELLIPSE_ARC );
93 shape->SetEllipseCenter( VECTOR2I( 0, 0 ) );
94 shape->SetEllipseMajorRadius( 40000 ); // 40 mm
95 shape->SetEllipseMinorRadius( 25000 ); // 25 mm
96 shape->SetEllipseRotation( EDA_ANGLE( 45.0, DEGREES_T ) );
97 shape->SetEllipseStartAngle( EDA_ANGLE( 20.0, DEGREES_T ) );
98 shape->SetEllipseEndAngle( EDA_ANGLE( 160.0, DEGREES_T ) );
99 shape->SetLayer( F_SilkS );
100 shape->SetWidth( 200 );
101 board->Add( shape.release(), ADD_MODE::APPEND, true );
102
103 KI_TEST::SCOPED_TEMP_DIR tmp( "kicad_qa_ellipse_roundtrip_arc" );
104 std::filesystem::path boardFile = tmp.Path() / "board.kicad_pcb";
105
106 KI_TEST::DumpBoardToFile( *board, boardFile );
107
108 std::unique_ptr<BOARD> reloaded = KI_TEST::ReadBoardFromFile( boardFile );
109 BOOST_REQUIRE( reloaded );
110
111 PCB_SHAPE* found = nullptr;
112
113 for( BOARD_ITEM* item : reloaded->Drawings() )
114 {
115 if( PCB_SHAPE* ps = dynamic_cast<PCB_SHAPE*>( item ) )
116 {
117 if( ps->GetShape() == SHAPE_T::ELLIPSE_ARC )
118 {
119 found = ps;
120 break;
121 }
122 }
123 }
124
125 BOOST_REQUIRE_MESSAGE( found, "Elliptical arc not found in reloaded board" );
126
127 BOOST_CHECK_EQUAL( found->GetEllipseCenter().x, 0 );
128 BOOST_CHECK_EQUAL( found->GetEllipseCenter().y, 0 );
129 BOOST_CHECK_EQUAL( found->GetEllipseMajorRadius(), 40000 );
130 BOOST_CHECK_EQUAL( found->GetEllipseMinorRadius(), 25000 );
131 BOOST_CHECK_CLOSE( found->GetEllipseRotation().AsDegrees(), 45.0, 1e-6 );
132 BOOST_CHECK_CLOSE( found->GetEllipseStartAngle().AsDegrees(), 20.0, 1e-6 );
133 BOOST_CHECK_CLOSE( found->GetEllipseEndAngle().AsDegrees(), 160.0, 1e-6 );
134}
135
136
137BOOST_AUTO_TEST_CASE( EllipseStrokeAndFillRoundTrip )
138{
139 auto board = std::make_unique<BOARD>();
140 auto shape = std::make_unique<PCB_SHAPE>( board.get() );
141 shape->SetShape( SHAPE_T::ELLIPSE );
142 shape->SetEllipseCenter( VECTOR2I( 50000, 50000 ) );
143 shape->SetEllipseMajorRadius( 30000 );
144 shape->SetEllipseMinorRadius( 20000 );
145 shape->SetEllipseRotation( ANGLE_0 );
146 shape->SetLayer( F_SilkS );
147 shape->SetStroke( STROKE_PARAMS( 250, LINE_STYLE::DASH ) );
148 shape->SetFillMode( FILL_T::FILLED_SHAPE );
149 board->Add( shape.release(), ADD_MODE::APPEND, true );
150
151 KI_TEST::SCOPED_TEMP_DIR tmp( "kicad_qa_ellipse_roundtrip_stroke_fill" );
152 std::filesystem::path boardFile = tmp.Path() / "board.kicad_pcb";
153
154 KI_TEST::DumpBoardToFile( *board, boardFile );
155
156 std::unique_ptr<BOARD> reloaded = KI_TEST::ReadBoardFromFile( boardFile );
157 BOOST_REQUIRE( reloaded );
158
159 PCB_SHAPE* found = nullptr;
160
161 for( BOARD_ITEM* item : reloaded->Drawings() )
162 {
163 if( PCB_SHAPE* ps = dynamic_cast<PCB_SHAPE*>( item ) )
164 {
165 if( ps->GetShape() == SHAPE_T::ELLIPSE )
166 {
167 found = ps;
168 break;
169 }
170 }
171 }
172
173 BOOST_REQUIRE_MESSAGE( found, "Ellipse not found in reloaded board" );
174 BOOST_CHECK_EQUAL( found->GetStroke().GetWidth(), 250 );
175 BOOST_CHECK( found->GetStroke().GetLineStyle() == LINE_STYLE::DASH );
176 BOOST_CHECK( found->GetFillMode() == FILL_T::FILLED_SHAPE );
177}
178
179
180BOOST_AUTO_TEST_CASE( EllipseLockedRoundTrip )
181{
182 auto board = std::make_unique<BOARD>();
183 auto shape = std::make_unique<PCB_SHAPE>( board.get() );
184 shape->SetShape( SHAPE_T::ELLIPSE );
185 shape->SetEllipseCenter( VECTOR2I( 0, 0 ) );
186 shape->SetEllipseMajorRadius( 10000 );
187 shape->SetEllipseMinorRadius( 5000 );
188 shape->SetEllipseRotation( ANGLE_0 );
189 shape->SetLayer( F_SilkS );
190 shape->SetWidth( 150 );
191 shape->SetLocked( true );
192 board->Add( shape.release(), ADD_MODE::APPEND, true );
193
194 KI_TEST::SCOPED_TEMP_DIR tmp( "kicad_qa_ellipse_roundtrip_locked" );
195 std::filesystem::path boardFile = tmp.Path() / "board.kicad_pcb";
196
197 KI_TEST::DumpBoardToFile( *board, boardFile );
198
199 std::unique_ptr<BOARD> reloaded = KI_TEST::ReadBoardFromFile( boardFile );
200 BOOST_REQUIRE( reloaded );
201
202 PCB_SHAPE* found = nullptr;
203
204 for( BOARD_ITEM* item : reloaded->Drawings() )
205 {
206 if( PCB_SHAPE* ps = dynamic_cast<PCB_SHAPE*>( item ) )
207 {
208 if( ps->GetShape() == SHAPE_T::ELLIPSE )
209 {
210 found = ps;
211 break;
212 }
213 }
214 }
215
216 BOOST_REQUIRE_MESSAGE( found, "Ellipse not found in reloaded board" );
217 BOOST_CHECK( found->IsLocked() );
218}
219
220
221BOOST_AUTO_TEST_CASE( EllipseNegativeRotationRoundTrip )
222{
223 auto board = std::make_unique<BOARD>();
224 auto shape = std::make_unique<PCB_SHAPE>( board.get() );
225 shape->SetShape( SHAPE_T::ELLIPSE );
226 shape->SetEllipseCenter( VECTOR2I( 0, 0 ) );
227 shape->SetEllipseMajorRadius( 40000 );
228 shape->SetEllipseMinorRadius( 20000 );
229 shape->SetEllipseRotation( EDA_ANGLE( -60.0, DEGREES_T ) );
230 shape->SetLayer( F_SilkS );
231 shape->SetWidth( 150 );
232 board->Add( shape.release(), ADD_MODE::APPEND, true );
233
234 KI_TEST::SCOPED_TEMP_DIR tmp( "kicad_qa_ellipse_roundtrip_negrot" );
235 std::filesystem::path boardFile = tmp.Path() / "board.kicad_pcb";
236
237 KI_TEST::DumpBoardToFile( *board, boardFile );
238
239 std::unique_ptr<BOARD> reloaded = KI_TEST::ReadBoardFromFile( boardFile );
240 BOOST_REQUIRE( reloaded );
241
242 PCB_SHAPE* found = nullptr;
243
244 for( BOARD_ITEM* item : reloaded->Drawings() )
245 {
246 if( PCB_SHAPE* ps = dynamic_cast<PCB_SHAPE*>( item ) )
247 {
248 if( ps->GetShape() == SHAPE_T::ELLIPSE )
249 {
250 found = ps;
251 break;
252 }
253 }
254 }
255
256 BOOST_REQUIRE_MESSAGE( found, "Ellipse not found in reloaded board" );
257 BOOST_CHECK_CLOSE( found->GetEllipseRotation().AsDegrees(), -60.0, 1e-6 );
258}
259
260
261BOOST_AUTO_TEST_CASE( EllipseArcStartEqualsEndRoundTrip )
262{
263 auto board = std::make_unique<BOARD>();
264 auto shape = std::make_unique<PCB_SHAPE>( board.get() );
265 shape->SetShape( SHAPE_T::ELLIPSE_ARC );
266 shape->SetEllipseCenter( VECTOR2I( 0, 0 ) );
267 shape->SetEllipseMajorRadius( 30000 );
268 shape->SetEllipseMinorRadius( 15000 );
269 shape->SetEllipseRotation( ANGLE_0 );
270 shape->SetEllipseStartAngle( EDA_ANGLE( 45.0, DEGREES_T ) );
271 shape->SetEllipseEndAngle( EDA_ANGLE( 45.0, DEGREES_T ) );
272 shape->SetLayer( F_SilkS );
273 shape->SetWidth( 150 );
274 board->Add( shape.release(), ADD_MODE::APPEND, true );
275
276 KI_TEST::SCOPED_TEMP_DIR tmp( "kicad_qa_ellipse_roundtrip_start_eq_end" );
277 std::filesystem::path boardFile = tmp.Path() / "board.kicad_pcb";
278
279 KI_TEST::DumpBoardToFile( *board, boardFile );
280
281 std::unique_ptr<BOARD> reloaded = KI_TEST::ReadBoardFromFile( boardFile );
282 BOOST_REQUIRE( reloaded );
283
284 PCB_SHAPE* found = nullptr;
285
286 for( BOARD_ITEM* item : reloaded->Drawings() )
287 {
288 if( PCB_SHAPE* ps = dynamic_cast<PCB_SHAPE*>( item ) )
289 {
290 if( ps->GetShape() == SHAPE_T::ELLIPSE_ARC )
291 {
292 found = ps;
293 break;
294 }
295 }
296 }
297
298 BOOST_REQUIRE_MESSAGE( found, "Elliptical arc not found in reloaded board" );
299 BOOST_CHECK_CLOSE( found->GetEllipseStartAngle().AsDegrees(), 45.0, 1e-6 );
300 BOOST_CHECK_CLOSE( found->GetEllipseEndAngle().AsDegrees(), 45.0, 1e-6 );
301}
302
303
304BOOST_AUTO_TEST_CASE( EllipseMinimumRadiiRoundTrip )
305{
306 auto board = std::make_unique<BOARD>();
307 auto shape = std::make_unique<PCB_SHAPE>( board.get() );
308 shape->SetShape( SHAPE_T::ELLIPSE );
309 shape->SetEllipseCenter( VECTOR2I( 0, 0 ) );
310 shape->SetEllipseMajorRadius( 1 );
311 shape->SetEllipseMinorRadius( 1 );
312 shape->SetEllipseRotation( ANGLE_0 );
313 shape->SetLayer( F_SilkS );
314 shape->SetWidth( 150 );
315 board->Add( shape.release(), ADD_MODE::APPEND, true );
316
317 KI_TEST::SCOPED_TEMP_DIR tmp( "kicad_qa_ellipse_roundtrip_minradii" );
318 std::filesystem::path boardFile = tmp.Path() / "board.kicad_pcb";
319
320 KI_TEST::DumpBoardToFile( *board, boardFile );
321
322 std::unique_ptr<BOARD> reloaded = KI_TEST::ReadBoardFromFile( boardFile );
323 BOOST_REQUIRE( reloaded );
324
325 PCB_SHAPE* found = nullptr;
326
327 for( BOARD_ITEM* item : reloaded->Drawings() )
328 {
329 if( PCB_SHAPE* ps = dynamic_cast<PCB_SHAPE*>( item ) )
330 {
331 if( ps->GetShape() == SHAPE_T::ELLIPSE )
332 {
333 found = ps;
334 break;
335 }
336 }
337 }
338
339 BOOST_REQUIRE_MESSAGE( found, "Ellipse not found in reloaded board" );
340 BOOST_CHECK( found->GetEllipseMajorRadius() >= 1 );
341 BOOST_CHECK( found->GetEllipseMinorRadius() >= 1 );
342}
343
344
345BOOST_AUTO_TEST_CASE( EllipseLargeRadiiRoundTrip )
346{
347 auto board = std::make_unique<BOARD>();
348 auto shape = std::make_unique<PCB_SHAPE>( board.get() );
349 shape->SetShape( SHAPE_T::ELLIPSE );
350 shape->SetEllipseCenter( VECTOR2I( 0, 0 ) );
351 shape->SetEllipseMajorRadius( 500000000 ); // 500 mm
352 shape->SetEllipseMinorRadius( 250000000 ); // 250 mm
353 shape->SetEllipseRotation( EDA_ANGLE( 15.0, DEGREES_T ) );
354 shape->SetLayer( F_SilkS );
355 shape->SetWidth( 150 );
356 board->Add( shape.release(), ADD_MODE::APPEND, true );
357
358 KI_TEST::SCOPED_TEMP_DIR tmp( "kicad_qa_ellipse_roundtrip_largeradii" );
359 std::filesystem::path boardFile = tmp.Path() / "board.kicad_pcb";
360
361 KI_TEST::DumpBoardToFile( *board, boardFile );
362
363 std::unique_ptr<BOARD> reloaded = KI_TEST::ReadBoardFromFile( boardFile );
364 BOOST_REQUIRE( reloaded );
365
366 PCB_SHAPE* found = nullptr;
367
368 for( BOARD_ITEM* item : reloaded->Drawings() )
369 {
370 if( PCB_SHAPE* ps = dynamic_cast<PCB_SHAPE*>( item ) )
371 {
372 if( ps->GetShape() == SHAPE_T::ELLIPSE )
373 {
374 found = ps;
375 break;
376 }
377 }
378 }
379
380 BOOST_REQUIRE_MESSAGE( found, "Ellipse not found in reloaded board" );
381 BOOST_CHECK_EQUAL( found->GetEllipseMajorRadius(), 500000000 );
382 BOOST_CHECK_EQUAL( found->GetEllipseMinorRadius(), 250000000 );
383}
384
385
386BOOST_AUTO_TEST_CASE( FootprintEllipseRoundTrip )
387{
388 auto board = std::make_unique<BOARD>();
389 auto fp = std::make_unique<FOOTPRINT>( board.get() );
390 fp->SetReference( "U1" );
391 fp->SetPosition( VECTOR2I( 100000, 100000 ) );
392
393 auto shape = std::make_unique<PCB_SHAPE>( fp.get() );
394 shape->SetShape( SHAPE_T::ELLIPSE );
395 shape->SetEllipseCenter( VECTOR2I( 0, 0 ) );
396 shape->SetEllipseMajorRadius( 20000 );
397 shape->SetEllipseMinorRadius( 10000 );
398 shape->SetEllipseRotation( EDA_ANGLE( 45.0, DEGREES_T ) );
399 shape->SetLayer( F_SilkS );
400 shape->SetWidth( 150 );
401 fp->Add( shape.release(), ADD_MODE::APPEND, true );
402
403 board->Add( fp.release(), ADD_MODE::APPEND, true );
404
405 KI_TEST::SCOPED_TEMP_DIR tmp( "kicad_qa_ellipse_roundtrip_fp" );
406 std::filesystem::path boardFile = tmp.Path() / "board.kicad_pcb";
407
408 KI_TEST::DumpBoardToFile( *board, boardFile );
409
410 std::unique_ptr<BOARD> reloaded = KI_TEST::ReadBoardFromFile( boardFile );
411 BOOST_REQUIRE( reloaded );
412
413 FOOTPRINT* fpFound = reloaded->Footprints().empty() ? nullptr : reloaded->Footprints().front();
414 BOOST_REQUIRE_MESSAGE( fpFound, "Footprint not found in reloaded board" );
415
416 PCB_SHAPE* found = nullptr;
417
418 for( BOARD_ITEM* item : fpFound->GraphicalItems() )
419 {
420 if( PCB_SHAPE* ps = dynamic_cast<PCB_SHAPE*>( item ) )
421 {
422 if( ps->GetShape() == SHAPE_T::ELLIPSE )
423 {
424 found = ps;
425 break;
426 }
427 }
428 }
429
430 BOOST_REQUIRE_MESSAGE( found, "fp_ellipse not found in reloaded footprint" );
431 BOOST_CHECK_EQUAL( found->GetEllipseMajorRadius(), 20000 );
432 BOOST_CHECK_EQUAL( found->GetEllipseMinorRadius(), 10000 );
433 BOOST_CHECK_CLOSE( found->GetEllipseRotation().AsDegrees(), 45.0, 1e-6 );
434}
435
436
437BOOST_AUTO_TEST_CASE( FootprintEllipseArcRoundTrip )
438{
439 auto board = std::make_unique<BOARD>();
440 auto fp = std::make_unique<FOOTPRINT>( board.get() );
441 fp->SetReference( "U2" );
442 fp->SetPosition( VECTOR2I( 0, 0 ) );
443
444 auto shape = std::make_unique<PCB_SHAPE>( fp.get() );
445 shape->SetShape( SHAPE_T::ELLIPSE_ARC );
446 shape->SetEllipseCenter( VECTOR2I( 0, 0 ) );
447 shape->SetEllipseMajorRadius( 15000 );
448 shape->SetEllipseMinorRadius( 8000 );
449 shape->SetEllipseRotation( EDA_ANGLE( -30.0, DEGREES_T ) );
450 shape->SetEllipseStartAngle( EDA_ANGLE( 10.0, DEGREES_T ) );
451 shape->SetEllipseEndAngle( EDA_ANGLE( 270.0, DEGREES_T ) );
452 shape->SetLayer( F_Fab );
453 shape->SetWidth( 100 );
454 fp->Add( shape.release(), ADD_MODE::APPEND, true );
455
456 board->Add( fp.release(), ADD_MODE::APPEND, true );
457
458 KI_TEST::SCOPED_TEMP_DIR tmp( "kicad_qa_ellipse_roundtrip_fp_arc" );
459 std::filesystem::path boardFile = tmp.Path() / "board.kicad_pcb";
460
461 KI_TEST::DumpBoardToFile( *board, boardFile );
462
463 std::unique_ptr<BOARD> reloaded = KI_TEST::ReadBoardFromFile( boardFile );
464 BOOST_REQUIRE( reloaded );
465
466 FOOTPRINT* fpFound = reloaded->Footprints().empty() ? nullptr : reloaded->Footprints().front();
467 BOOST_REQUIRE_MESSAGE( fpFound, "Footprint not found in reloaded board" );
468
469 PCB_SHAPE* found = nullptr;
470
471 for( BOARD_ITEM* item : fpFound->GraphicalItems() )
472 {
473 if( PCB_SHAPE* ps = dynamic_cast<PCB_SHAPE*>( item ) )
474 {
475 if( ps->GetShape() == SHAPE_T::ELLIPSE_ARC )
476 {
477 found = ps;
478 break;
479 }
480 }
481 }
482
483 BOOST_REQUIRE_MESSAGE( found, "fp_ellipse_arc not found in reloaded footprint" );
484 BOOST_CHECK_EQUAL( found->GetEllipseMajorRadius(), 15000 );
486 BOOST_CHECK_CLOSE( found->GetEllipseRotation().AsDegrees(), -30.0, 1e-6 );
487 BOOST_CHECK_CLOSE( found->GetEllipseStartAngle().AsDegrees(), 10.0, 1e-6 );
488 BOOST_CHECK_CLOSE( found->GetEllipseEndAngle().AsDegrees(), 270.0, 1e-6 );
489}
490
491
492BOOST_AUTO_TEST_CASE( EllipseArcWrapAroundAnglesRoundTrip )
493{
494 auto board = std::make_unique<BOARD>();
495 auto shape = std::make_unique<PCB_SHAPE>( board.get() );
496 shape->SetShape( SHAPE_T::ELLIPSE_ARC );
497 shape->SetEllipseCenter( VECTOR2I( 0, 0 ) );
498 shape->SetEllipseMajorRadius( 30000 );
499 shape->SetEllipseMinorRadius( 15000 );
500 shape->SetEllipseRotation( ANGLE_0 );
501 shape->SetEllipseStartAngle( EDA_ANGLE( 350.0, DEGREES_T ) );
502 shape->SetEllipseEndAngle( EDA_ANGLE( 370.0, DEGREES_T ) );
503 shape->SetLayer( F_SilkS );
504 shape->SetWidth( 150 );
505 board->Add( shape.release(), ADD_MODE::APPEND, true );
506
507 KI_TEST::SCOPED_TEMP_DIR tmp( "kicad_qa_ellipse_roundtrip_wraparound" );
508 std::filesystem::path boardFile = tmp.Path() / "board.kicad_pcb";
509
510 KI_TEST::DumpBoardToFile( *board, boardFile );
511
512 std::unique_ptr<BOARD> reloaded = KI_TEST::ReadBoardFromFile( boardFile );
513 BOOST_REQUIRE( reloaded );
514
515 PCB_SHAPE* found = nullptr;
516
517 for( BOARD_ITEM* item : reloaded->Drawings() )
518 {
519 if( PCB_SHAPE* ps = dynamic_cast<PCB_SHAPE*>( item ) )
520 {
521 if( ps->GetShape() == SHAPE_T::ELLIPSE_ARC )
522 {
523 found = ps;
524 break;
525 }
526 }
527 }
528
529 BOOST_REQUIRE_MESSAGE( found, "Elliptical arc not found in reloaded board" );
530 BOOST_CHECK_CLOSE( found->GetEllipseStartAngle().AsDegrees(), 350.0, 1e-6 );
531 BOOST_CHECK_CLOSE( found->GetEllipseEndAngle().AsDegrees(), 370.0, 1e-6 );
532}
533
534
535BOOST_AUTO_TEST_CASE( EllipseArcNegativeStartAngleRoundTrip )
536{
537 auto board = std::make_unique<BOARD>();
538 auto shape = std::make_unique<PCB_SHAPE>( board.get() );
539 shape->SetShape( SHAPE_T::ELLIPSE_ARC );
540 shape->SetEllipseCenter( VECTOR2I( 0, 0 ) );
541 shape->SetEllipseMajorRadius( 20000 );
542 shape->SetEllipseMinorRadius( 10000 );
543 shape->SetEllipseRotation( ANGLE_0 );
544 shape->SetEllipseStartAngle( EDA_ANGLE( -45.0, DEGREES_T ) );
545 shape->SetEllipseEndAngle( EDA_ANGLE( 90.0, DEGREES_T ) );
546 shape->SetLayer( F_SilkS );
547 shape->SetWidth( 150 );
548 board->Add( shape.release(), ADD_MODE::APPEND, true );
549
550 KI_TEST::SCOPED_TEMP_DIR tmp( "kicad_qa_ellipse_roundtrip_negstart" );
551 std::filesystem::path boardFile = tmp.Path() / "board.kicad_pcb";
552
553 KI_TEST::DumpBoardToFile( *board, boardFile );
554
555 std::unique_ptr<BOARD> reloaded = KI_TEST::ReadBoardFromFile( boardFile );
556 BOOST_REQUIRE( reloaded );
557
558 PCB_SHAPE* found = nullptr;
559
560 for( BOARD_ITEM* item : reloaded->Drawings() )
561 {
562 if( PCB_SHAPE* ps = dynamic_cast<PCB_SHAPE*>( item ) )
563 {
564 if( ps->GetShape() == SHAPE_T::ELLIPSE_ARC )
565 {
566 found = ps;
567 break;
568 }
569 }
570 }
571
572 BOOST_REQUIRE_MESSAGE( found, "Elliptical arc not found in reloaded board" );
573 BOOST_CHECK_CLOSE( found->GetEllipseStartAngle().AsDegrees(), -45.0, 1e-6 );
574 BOOST_CHECK_CLOSE( found->GetEllipseEndAngle().AsDegrees(), 90.0, 1e-6 );
575}
576
577
578BOOST_AUTO_TEST_CASE( EllipseOnEdgeCutsRoundTrip )
579{
580 auto board = std::make_unique<BOARD>();
581 auto shape = std::make_unique<PCB_SHAPE>( board.get() );
582 shape->SetShape( SHAPE_T::ELLIPSE );
583 shape->SetEllipseCenter( VECTOR2I( 100000, 100000 ) );
584 shape->SetEllipseMajorRadius( 50000 );
585 shape->SetEllipseMinorRadius( 30000 );
586 shape->SetEllipseRotation( EDA_ANGLE( 10.0, DEGREES_T ) );
587 shape->SetLayer( Edge_Cuts );
588 shape->SetWidth( 150 );
589 board->Add( shape.release(), ADD_MODE::APPEND, true );
590
591 KI_TEST::SCOPED_TEMP_DIR tmp( "kicad_qa_ellipse_roundtrip_edgecuts" );
592 std::filesystem::path boardFile = tmp.Path() / "board.kicad_pcb";
593
594 KI_TEST::DumpBoardToFile( *board, boardFile );
595
596 std::unique_ptr<BOARD> reloaded = KI_TEST::ReadBoardFromFile( boardFile );
597 BOOST_REQUIRE( reloaded );
598
599 PCB_SHAPE* found = nullptr;
600
601 for( BOARD_ITEM* item : reloaded->Drawings() )
602 {
603 if( PCB_SHAPE* ps = dynamic_cast<PCB_SHAPE*>( item ) )
604 {
605 if( ps->GetShape() == SHAPE_T::ELLIPSE )
606 {
607 found = ps;
608 break;
609 }
610 }
611 }
612
613 BOOST_REQUIRE_MESSAGE( found, "Ellipse not found in reloaded board" );
614 BOOST_CHECK( found->GetLayer() == Edge_Cuts );
615}
616
617
618BOOST_AUTO_TEST_CASE( EllipseOnBackCopperRoundTrip )
619{
620 auto board = std::make_unique<BOARD>();
621 auto shape = std::make_unique<PCB_SHAPE>( board.get() );
622 shape->SetShape( SHAPE_T::ELLIPSE );
623 shape->SetEllipseCenter( VECTOR2I( 0, 0 ) );
624 shape->SetEllipseMajorRadius( 25000 );
625 shape->SetEllipseMinorRadius( 15000 );
626 shape->SetEllipseRotation( ANGLE_0 );
627 shape->SetLayer( B_Cu );
628 shape->SetWidth( 200 );
629 board->Add( shape.release(), ADD_MODE::APPEND, true );
630
631 KI_TEST::SCOPED_TEMP_DIR tmp( "kicad_qa_ellipse_roundtrip_bcu" );
632 std::filesystem::path boardFile = tmp.Path() / "board.kicad_pcb";
633
634 KI_TEST::DumpBoardToFile( *board, boardFile );
635
636 std::unique_ptr<BOARD> reloaded = KI_TEST::ReadBoardFromFile( boardFile );
637 BOOST_REQUIRE( reloaded );
638
639 PCB_SHAPE* found = nullptr;
640
641 for( BOARD_ITEM* item : reloaded->Drawings() )
642 {
643 if( PCB_SHAPE* ps = dynamic_cast<PCB_SHAPE*>( item ) )
644 {
645 if( ps->GetShape() == SHAPE_T::ELLIPSE )
646 {
647 found = ps;
648 break;
649 }
650 }
651 }
652
653 BOOST_REQUIRE_MESSAGE( found, "Ellipse not found in reloaded board" );
654 BOOST_CHECK( found->GetLayer() == B_Cu );
655}
656
657
General utilities for PCB file IO for QA programs.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:85
bool IsLocked() const override
double AsDegrees() const
Definition eda_angle.h:115
int GetEllipseMinorRadius() const
Definition eda_shape.h:403
const VECTOR2I & GetEllipseCenter() const
Definition eda_shape.h:385
EDA_ANGLE GetEllipseEndAngle() const
Definition eda_shape.h:431
FILL_T GetFillMode() const
Definition eda_shape.h:150
int GetEllipseMajorRadius() const
Definition eda_shape.h:394
EDA_ANGLE GetEllipseRotation() const
Definition eda_shape.h:412
EDA_ANGLE GetEllipseStartAngle() const
Definition eda_shape.h:422
DRAWINGS & GraphicalItems()
Definition footprint.h:358
const std::filesystem::path & Path() const
Get the path to the temporary directory as a std::filesystem::path.
Definition file_utils.h:61
STROKE_PARAMS GetStroke() const override
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition pcb_shape.h:70
Simple container to manage line stroke parameters.
int GetWidth() const
LINE_STYLE GetLineStyle() const
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:448
@ DEGREES_T
Definition eda_angle.h:30
@ FILLED_SHAPE
Fill with object color.
Definition eda_fill.h:31
@ ELLIPSE
Definition eda_shape.h:62
@ ELLIPSE_ARC
Definition eda_shape.h:63
@ Edge_Cuts
Definition layer_ids.h:108
@ B_Cu
Definition layer_ids.h:61
@ F_Fab
Definition layer_ids.h:115
@ F_SilkS
Definition layer_ids.h:96
std::unique_ptr< BOARD > ReadBoardFromFile(const std::filesystem::path &aFilename)
std::unique_ptr< BOARD > ReadBoardFromFileOrStream(const std::string &aFilename, std::istream &aFallback)
Read a board from a file, or another stream, as appropriate.
void DumpBoardToFile(BOARD &board, const std::filesystem::path &aFilename)
Utility function to simply write a Board out to a file.
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_AUTO_TEST_CASE(ClosedEllipseRoundTrip)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
BOOST_CHECK_EQUAL(result, "25.4")
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708