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