KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_shape_arc.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, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
25#include <boost/test/data/test_case.hpp>
26
28#include <geometry/shape_arc.h>
31
33#include <qa_utils/numeric.h>
34
35#include "geom_test_utils.h"
36
37BOOST_AUTO_TEST_SUITE( ShapeArc )
38
39
44{
53};
54
61static void CheckArcGeom( const SHAPE_ARC& aArc, const ARC_PROPERTIES& aProps, const int aSynErrIU = 1 )
62{
63 // Angular error - note this can get quite large for very small arcs,
64 // as the integral position rounding has a relatively greater effect
65 const double angle_tol_deg = 2.0;
66
67 // Position error - rounding to nearest integer
68 const int pos_tol = 1;
69
70 BOOST_CHECK_PREDICATE( KI_TEST::IsVecWithinTol<VECTOR2I>,
71 ( aProps.m_start_point )( aProps.m_start_point )( pos_tol ) );
72
73 BOOST_CHECK_PREDICATE( KI_TEST::IsVecWithinTol<VECTOR2I>,
74 ( aArc.GetP1() )( aProps.m_end_point )( pos_tol ) );
75
76 BOOST_CHECK_PREDICATE( KI_TEST::IsVecWithinTol<VECTOR2I>,
77 ( aArc.GetCenter() )( aProps.m_center_point )( aSynErrIU ) );
78
79 BOOST_CHECK_PREDICATE( KI_TEST::IsWithinWrapped<double>,
80 ( aArc.GetCentralAngle().AsDegrees() )( aProps.m_center_angle )( 360.0 )( angle_tol_deg ) );
81
82 BOOST_CHECK_PREDICATE( KI_TEST::IsWithinWrapped<double>,
83 ( aArc.GetStartAngle().AsDegrees() )( aProps.m_start_angle )( 360.0 )( angle_tol_deg ) );
84
85 BOOST_CHECK_PREDICATE( KI_TEST::IsWithinWrapped<double>,
86 ( aArc.GetEndAngle().AsDegrees() )( aProps.m_end_angle )( 360.0 )( angle_tol_deg ) );
87
88 BOOST_CHECK_PREDICATE( KI_TEST::IsWithin<double>,
89 ( aArc.GetRadius() )( aProps.m_radius )( aSynErrIU ) );
90
91 // Angle normalization contracts
92 BOOST_TEST( aArc.GetStartAngle().AsDegrees() >= 0.0 );
93 BOOST_TEST( aArc.GetStartAngle().AsDegrees() <= 360.0 );
94
95 BOOST_TEST( aArc.GetEndAngle().AsDegrees() >= 0.0 );
96 BOOST_TEST( aArc.GetEndAngle().AsDegrees() <= 360.0 );
97
98 BOOST_TEST( aArc.GetCentralAngle().AsDegrees() >= -360.0 );
99 BOOST_TEST( aArc.GetCentralAngle().AsDegrees() <= 360.0 );
100
102 const SEG chord = aArc.GetChord();
103
104 BOOST_CHECK_PREDICATE( KI_TEST::IsVecWithinTol<VECTOR2I>,
105 ( chord.A )( aProps.m_start_point )( pos_tol ) );
106
107 BOOST_CHECK_PREDICATE( KI_TEST::IsVecWithinTol<VECTOR2I>,
108 ( chord.B )( aProps.m_end_point )( pos_tol ) );
109
111 BOOST_CHECK_EQUAL( aArc.IsSolid(), true );
112
113 BOOST_CHECK_PREDICATE( KI_TEST::IsBoxWithinTol<BOX2I>,
114 ( aArc.BBox() )( aProps.m_bbox )( pos_tol ) );
115
117}
118
119
126static void CheckArc( const SHAPE_ARC& aArc, const ARC_PROPERTIES& aProps, const int aSynErrIU = 1 )
127{
128 // Check the original arc
129 CheckArcGeom( aArc, aProps, aSynErrIU );
130
131 // Test the Clone function (also tests copy-ctor)
132 std::unique_ptr<SHAPE> new_shape{ aArc.Clone() };
133
134 BOOST_CHECK_EQUAL( new_shape->Type(), SH_ARC );
135
136 SHAPE_ARC* new_arc = dynamic_cast<SHAPE_ARC*>( new_shape.get() );
137
138 BOOST_REQUIRE( new_arc != nullptr );
139
141 CheckArcGeom( *new_arc, aProps, aSynErrIU );
142}
143
148{
149 auto arc = SHAPE_ARC();
150
151 BOOST_CHECK_EQUAL( arc.GetWidth(), 0 );
152
153 static ARC_PROPERTIES null_props{
154 { 0, 0 },
155 { 0, 0 },
156 { 0, 0 },
157 0,
158 0,
159 0,
160 0,
161 };
162
163 CheckArc( arc, null_props );
164}
165
166
171{
175};
176
178{
181
184
187};
188
189
190static const std::vector<ARC_SME_CASE> arc_sme_cases = {
191 {
192 "S(-100,0), M(0,100), E(100,0)",
193 {
194 { -100, 0 },
195 { 0, 100 },
196 { 100, 0 },
197 },
198 0,
199 {
200 { 0, 0 },
201 { -100, 0 },
202 { 100, 0 },
203 180,
204 180,
205 0,
206 100,
207 { { -100, 0 }, { 200, 100 } },
208 },
209 },
210 {
211 "S(100,0), M(0,100), E(-100,0) (reversed)",
212 {
213 { 100, 0 },
214 { 0, 100 },
215 { -100, 0 },
216 },
217 0,
218 {
219 { 0, 0 },
220 { 100, 0 },
221 { -100, 0 },
222 -180,
223 0,
224 180,
225 100,
226 { { -100, 0 }, { 200, 100 } },
227 },
228 },
229 {
230 // This data has a midpoint not exactly at the midway point of the arc.
231 // This should be corrected by the constructor.
232 // The mid point should be at about (-71, -71) for a 270 degree arc, with the
233 // bottom right quadrant open.
234 "S(100,0), M(-100,0), E(0,100) (bad midpoint)",
235 {
236 { 100, 0 },
237 { -100, 0 },
238 { 0, 100 },
239 },
240 0,
241 {
242 { 0, 0 },
243 { 100, 0 },
244 { 0, 100 },
245 -270,
246 0,
247 90,
248 100,
249 { { -100, -100 }, { 200, 200 } },
250 },
251 }
252};
253
254
255BOOST_DATA_TEST_CASE( BasicSMEGeom, boost::unit_test::data::make( arc_sme_cases ), c )
256{
257 const SHAPE_ARC this_arc{
258 c.m_geom.m_start_point,
259 c.m_geom.m_mid_point,
260 c.m_geom.m_end_point,
261 c.m_width,
262 };
263
264 CheckArc( this_arc, c.m_properties );
265}
266
267
272{
276};
277
278
280{
283
286
289};
290
291
292static const std::vector<ARC_CPA_CASE> arc_cases = {
293 {
294 "C(0,0) 114 + 360 degree",
295 {
296 { 0, 0 },
297 { -306451, 687368 },
298 360,
299 },
300 0,
301 {
302 { 0, 0 },
303 { -306451, 687368 },
304 { -306451, 687368 },
305 360,
306 113.95929,
307 113.95929,
308 752587,
309 { { -752587, -752587 }, { 1505174, 1505174 } },
310 },
311 },
312 {
313 "C(0,0) 180 + 360 degree",
314 {
315 { 0, 0 },
316 { -100, 0 },
317 360,
318 },
319 0,
320 {
321 { 0, 0 },
322 { -100, 0 },
323 { -100, 0 },
324 360,
325 180,
326 180,
327 100,
328 { { -100, -100 }, { 200, 200 } },
329 },
330 },
331 {
332 "C(0,0) 180 + 90 degree",
333 {
334 { 0, 0 },
335 { -100, 0 },
336 90,
337 },
338 0,
339 {
340 { 0, 0 },
341 { -100, 0 },
342 { 0, -100 },
343 90,
344 180,
345 270,
346 100,
347 { { -100, -100 }, { 100, 100 } },
348 },
349 },
350 {
351 "C(100,200) 0 - 30 degree",
352 {
353 { 100, 200 },
354 { 300, 200 },
355 -30,
356 },
357 0,
358 {
359 { 100, 200 },
360 { 300, 200 },
361 { 273, 100 }, // 200 * sin(30) = 100, 200* cos(30) = 173
362 -30,
363 0,
364 330,
365 200,
366 { { 273, 100 }, { 27, 100 } },
367 },
368 },
369 {
370 // This is a "fan shape" which includes the top quadrant point,
371 // so it exercises the bounding box code (centre and end points
372 // do not contain the top quadrant)
373 "C(0,0) 30 + 120 degree",
374 {
375 { 0, 0 },
376 { 17320, 10000 },
377 120,
378 },
379 0,
380 {
381 { 0, 0 },
382 { 17320, 10000 },
383 { -17320, 10000 }, // 200 * sin(30) = 100, 200* cos(30) = 173
384 120,
385 30,
386 150,
387 20000,
388 // bbox defined by: centre, top quadrant point, two endpoints
389 { { -17320, 10000 }, { 17320 * 2, 10000 } },
390 },
391 },
392 {
393 // An arc that covers three quadrant points (L/R, bottom)
394 "C(0,0) 150 + 240 degree",
395 {
396 { 0, 0 },
397 { -17320, 10000 },
398 240,
399 },
400 0,
401 {
402 { 0, 0 },
403 { -17320, 10000 },
404 { 17320, 10000 },
405 240,
406 150,
407 30,
408 20000,
409 // bbox defined by: L/R quads, bottom quad and start/end
410 { { -20000, -20000 }, { 40000, 30000 } },
411 },
412 },
413 {
414 // Same as above but reverse direction
415 "C(0,0) 30 - 300 degree",
416 {
417 { 0, 0 },
418 { 17320, 10000 },
419 -240,
420 },
421 0,
422 {
423 { 0, 0 },
424 { 17320, 10000 },
425 { -17320, 10000 },
426 -240,
427 30,
428 150,
429 20000,
430 // bbox defined by: L/R quads, bottom quad and start/end
431 { { -20000, -20000 }, { 40000, 30000 } },
432 },
433 },
434};
435
436
437BOOST_DATA_TEST_CASE( BasicCPAGeom, boost::unit_test::data::make( arc_cases ), c )
438{
439 const SHAPE_ARC this_arc{
440 c.m_geom.m_center_point,
441 c.m_geom.m_start_point,
442 EDA_ANGLE( c.m_geom.m_center_angle, DEGREES_T ),
443 c.m_width,
444 };
445
446 CheckArc( this_arc, c.m_properties );
447}
448
449
450
455{
459};
460
461
463{
466
469
472};
473
474
475static const std::vector<ARC_TTR_CASE> arc_ttr_cases = {
476 {
477 "90 degree segments intersecting",
478 {
479 { 0, 0, 0, 1000 },
480 { 0, 0, 1000, 0 },
481 1000,
482 },
483 0,
484 {
485 { 1000, 1000 },
486 { 0, 1000 }, //start on first segment
487 { 1000, 0 }, //end on second segment
488 90, //positive angle due to start/end
489 180,
490 270,
491 1000,
492 { { 0, 0 }, { 1000, 1000 } },
493 }
494 },
495 {
496 "45 degree segments intersecting",
497 {
498 { 0, 0, 0, 1000 },
499 { 0, 0, 1000, 1000 },
500 1000,
501 },
502 0,
503 {
504 { 1000, 2414 },
505 { 0, 2414 }, //start on first segment
506 { 1707, 1707 }, //end on second segment
507 135, //positive angle due to start/end
508 180,
509 315,
510 1000,
511 { { 0, 1414 }, { 1707, 1000 } },
512 }
513 },
514 {
515 "135 degree segments intersecting",
516 {
517 { 0, 0, 0, 1000 },
518 { 0, 0, 1000, -1000 },
519 1000,
520 },
521 0,
522 {
523 { 1000, 414 },
524 { 0, 414 }, //start on first segment ( radius * tan(45 /2) )
525 { 293, -293 }, //end on second segment (radius * 1-cos(45)) )
526 45, //positive angle due to start/end
527 180,
528 225,
529 1000,
530 { { 0, -293 }, { 293, 707 } },
531 }
532 }
533
534
535};
536
537
538BOOST_DATA_TEST_CASE( BasicTTRGeom, boost::unit_test::data::make( arc_ttr_cases ), c )
539{
540 for( int testCase = 0; testCase < 8; ++testCase )
541 {
542 SEG seg1 = c.m_geom.m_segment_1;
543 SEG seg2 = c.m_geom.m_segment_2;
544 ARC_PROPERTIES props = c.m_properties;
545
546 if( testCase > 3 )
547 {
548 //Swap input segments.
549 seg1 = c.m_geom.m_segment_2;
550 seg2 = c.m_geom.m_segment_1;
551
552 //The result should swap start and end points and invert the angles:
553 props.m_end_point = c.m_properties.m_start_point;
554 props.m_start_point = c.m_properties.m_end_point;
555 props.m_start_angle = c.m_properties.m_end_angle;
556 props.m_end_angle = c.m_properties.m_start_angle;
557 props.m_center_angle = -c.m_properties.m_center_angle;
558 }
559
560 //Test all combinations of start and end points for the segments
561 if( ( testCase % 4 ) == 1 || ( testCase % 4 ) == 3 )
562 {
563 //Swap start and end points for seg1
564 VECTOR2I temp = seg1.A;
565 seg1.A = seg1.B;
566 seg1.B = temp;
567 }
568
569 if( ( testCase % 4 ) == 2 || ( testCase % 4 ) == 3 )
570 {
571 //Swap start and end points for seg2
572 VECTOR2I temp = seg2.A;
573 seg2.A = seg2.B;
574 seg2.B = temp;
575 }
576
577 const auto this_arc = SHAPE_ARC{ seg1, seg2,
578 c.m_geom.m_radius, c.m_width };
579
580 // Error of 4 IU permitted for the center and radius calculation
582 }
583}
584
585
589struct ARC_START_END_CENTER
590{
591 VECTOR2I m_start;
592 VECTOR2I m_end;
593 VECTOR2I m_center;
594};
595
596
598{
600 ARC_START_END_CENTER m_geom;
601
604
607};
608
609
610
611static const std::vector<ARC_SEC_CASE> arc_sec_cases = {
612 { "180 deg, clockwise", { { 100, 0 }, { 0, 0 }, { 50, 0 } }, true, { 50, -50 } },
613 { "180 deg, anticlockwise", { { 100, 0 }, { 0, 0 }, { 50, 0 } }, false, { 50, 50 } },
614 { "180 deg flipped, clockwise", { { 0, 0 }, { 100, 0 }, { 50, 0 } }, true, { 50, 50 } },
615 { "180 deg flipped, anticlockwise", { { 0, 0 }, { 100, 0 }, { 50, 0 } }, false, { 50, -50 } },
616 { "90 deg, clockwise", { { -100, 0 }, { 0, 100 }, { 0, 0 } }, true, { -71, 71 } },
617 { "90 deg, anticlockwise", { { -100, 0 }, { 0, 100 }, { 0, 0 } }, false, { 71, -71 } },
618};
619
620
621BOOST_DATA_TEST_CASE( BasicSECGeom, boost::unit_test::data::make( arc_sec_cases ), c )
622{
623 VECTOR2I start = c.m_geom.m_start;
624 VECTOR2I end = c.m_geom.m_end;
625 VECTOR2I center = c.m_geom.m_center;
626 bool cw = c.m_clockwise;
627
630
631 BOOST_CHECK_EQUAL( this_arc.GetArcMid(), c.m_expected_mid );
632}
633
634
636{
643};
644
645static const std::vector<ARC_CICLE_COLLIDE_CASE> arc_circle_collide_cases = {
646 { " Issue 20336, large arc", { { 183000000, 65710001}, {150496913, 147587363},{116291153, 66406583}}, 2000000 / 2, {116300000, 133100000}, 300000, true, 53319 }
647};
648
649
650BOOST_DATA_TEST_CASE( CollideCircle, boost::unit_test::data::make( arc_circle_collide_cases ), c )
651{
652 SHAPE_ARC arc( c.m_geom.m_start_point, c.m_geom.m_mid_point, c.m_geom.m_end_point, 0 );
653 SHAPE_CIRCLE circle( c.m_circle_center, c.m_circle_radius );
654
655 // Test a zero width arc (distance should equal the clearance)
656 BOOST_TEST_CONTEXT( "Test Clearance" )
657 {
658 int dist = -1;
659 BOOST_CHECK_EQUAL( arc.Collide( &circle, c.m_arc_clearance, &dist ), c.m_exp_result );
660 BOOST_CHECK_EQUAL( dist, c.m_exp_distance );
661 }
662
663 // Test by changing the width of the arc (distance should equal zero)
664 BOOST_TEST_CONTEXT( "Test Width" )
665 {
666 int dist = -1;
667 arc.SetWidth( c.m_arc_clearance * 2 );
668 BOOST_CHECK_EQUAL( arc.Collide( &circle, 0, &dist ), c.m_exp_result );
669
670 if( c.m_exp_result )
671 BOOST_CHECK_EQUAL( dist, 0 );
672 else
673 BOOST_CHECK_EQUAL( dist, -1 );
674 }
675}
676
677
679{
685};
686
687
688static const std::vector<ARC_PT_COLLIDE_CASE> arc_pt_collide_cases = {
689 { " 270deg, 0 cl, 0 deg ", { { 0, 0 }, { 100, 0 }, 270.0 }, 0, { 100, 0 }, true, 0 },
690 { " 270deg, 0 cl, 90 deg ", { { 0, 0 }, { 100, 0 }, 270.0 }, 0, { 0, 100 }, true, 0 },
691 { " 270deg, 0 cl, 180 deg ", { { 0, 0 }, { 100, 0 }, 270.0 }, 0, { -100, 0 }, true, 0 },
692 { " 270deg, 0 cl, 270 deg ", { { 0, 0 }, { 100, 0 }, 270.0 }, 0, { 0, -100 }, true, 0 },
693 { " 270deg, 0 cl, 45 deg ", { { 0, 0 }, { 100, 0 }, 270.0 }, 0, { 71, 71 }, true, 0 },
694 { " 270deg, 0 cl, -45 deg ", { { 0, 0 }, { 100, 0 }, 270.0 }, 0, { 71, -71 }, false, -1 },
695 { "-270deg, 0 cl, 0 deg ", { { 0, 0 }, { 100, 0 }, -270.0 }, 0, { 100, 0 }, true, 0 },
696 { "-270deg, 0 cl, 90 deg ", { { 0, 0 }, { 100, 0 }, -270.0 }, 0, { 0, 100 }, true, 0 },
697 { "-270deg, 0 cl, 180 deg ", { { 0, 0 }, { 100, 0 }, -270.0 }, 0, { -100, 0 }, true, 0 },
698 { "-270deg, 0 cl, 270 deg ", { { 0, 0 }, { 100, 0 }, -270.0 }, 0, { 0, -100 }, true, 0 },
699 { "-270deg, 0 cl, 45 deg ", { { 0, 0 }, { 100, 0 }, -270.0 }, 0, { 71, 71 }, false, -1 },
700 { "-270deg, 0 cl, -45 deg ", { { 0, 0 }, { 100, 0 }, -270.0 }, 0, { 71, -71 }, true, 0 },
701 { " 270deg, 5 cl, 0 deg, 5 pos X", { { 0, 0 }, { 100, 0 }, 270.0 }, 5, { 105, 0 }, true, 5 },
702 { " 270deg, 5 cl, 0 deg, 5 pos Y", { { 0, 0 }, { 100, 0 }, 270.0 }, 5, { 100, -5 }, true, 5 },
703 { " 270deg, 5 cl, 90 deg, 5 pos", { { 0, 0 }, { 100, 0 }, 270.0 }, 5, { 0, 105 }, true, 5 },
704 { " 270deg, 5 cl, 180 deg, 5 pos", { { 0, 0 }, { 100, 0 }, 270.0 }, 5, { -105, 0 }, true, 5 },
705 { " 270deg, 5 cl, 270 deg, 5 pos", { { 0, 0 }, { 100, 0 }, 270.0 }, 5, { 0, -105 }, true, 5 },
706 { " 270deg, 5 cl, 0 deg, 5 neg", { { 0, 0 }, { 100, 0 }, 270.0 }, 5, { 105, 0 }, true, 5 },
707 { " 270deg, 5 cl, 90 deg, 5 neg", { { 0, 0 }, { 100, 0 }, 270.0 }, 5, { 0, 105 }, true, 5 },
708 { " 270deg, 5 cl, 180 deg, 5 neg", { { 0, 0 }, { 100, 0 }, 270.0 }, 5, { -105, 0 }, true, 5 },
709 { " 270deg, 5 cl, 270 deg, 5 neg", { { 0, 0 }, { 100, 0 }, 270.0 }, 5, { 0, -105 }, true, 5 },
710 { " 270deg, 5 cl, 45 deg, 5 pos", { { 0, 0 }, { 100, 0 }, 270.0 }, 5, { 74, 75 }, true, 5 }, // 74.246, -74.246
711 { " 270deg, 5 cl, -45 deg, 5 pos", { { 0, 0 }, { 100, 0 }, 270.0 }, 5, { 74, -75 }, false, -1 }, //74.246, -74.246
712 { " 270deg, 5 cl, 45 deg, 5 neg", { { 0, 0 }, { 100, 0 }, 270.0 }, 5, { 67, 67 }, true, 5 }, // 67.17, 67.17
713 { " 270deg, 5 cl, -45 deg, 5 neg", { { 0, 0 }, { 100, 0 }, 270.0 }, 5, { 67, -67 }, false, -1 }, // 67.17, -67.17
714 { " 270deg, 4 cl, 0 deg pos", { { 0, 0 }, { 100, 0 }, 270.0 }, 4, { 105, 0 }, false, -1 },
715 { " 270deg, 4 cl, 90 deg pos", { { 0, 0 }, { 100, 0 }, 270.0 }, 4, { 0, 105 }, false, -1 },
716 { " 270deg, 4 cl, 180 deg pos", { { 0, 0 }, { 100, 0 }, 270.0 }, 4, { -105, 0 }, false, -1 },
717 { " 270deg, 4 cl, 270 deg pos", { { 0, 0 }, { 100, 0 }, 270.0 }, 4, { 0, -105 }, false, -1 },
718 { " 90deg, 0 cl, 0 deg ", { { 0, 0 }, { 71, -71 }, 90.0 }, 0, { 71, -71 }, true, 0 },
719 { " 90deg, 0 cl, 45 deg ", { { 0, 0 }, { 71, -71 }, 90.0 }, 0, { 100, 0 }, true, 0 },
720 { " 90deg, 0 cl, 90 deg ", { { 0, 0 }, { 71, -71 }, 90.0 }, 0, { 71, 71 }, true, 0 },
721 { " 90deg, 0 cl, 135 deg ", { { 0, 0 }, { 71, -71 }, 90.0 }, 0, { 0, -100 }, false, -1 },
722 { " 90deg, 0 cl, -45 deg ", { { 0, 0 }, { 71, -71 }, 90.0 }, 0, { 0, 100 }, false, -1 },
723 { " -90deg, 0 cl, 0 deg ", { { 0, 0 }, { 71, 71 }, -90.0 }, 0, { 71, -71 }, true, 0 },
724 { " -90deg, 0 cl, 45 deg ", { { 0, 0 }, { 71, 71 }, -90.0 }, 0, { 100, 0 }, true, 0 },
725 { " -90deg, 0 cl, 90 deg ", { { 0, 0 }, { 71, 71 }, -90.0 }, 0, { 71, 71 }, true, 0 },
726 { " -90deg, 0 cl, 135 deg ", { { 0, 0 }, { 71, 71 }, -90.0 }, 0, { 0, -100 }, false, -1 },
727 { " -90deg, 0 cl, -45 deg ", { { 0, 0 }, { 71, 71 }, -90.0 }, 0, { 0, 100 }, false, -1 },
728 { "issue 11358 collide",
729 { { 119888000, 60452000 }, { 120904000, 60452000 }, 360.0 },
730 0,
731 { 120395500, 59571830 },
732 true,
733 0 },
734 { "issue 11358 dist",
735 { { 119888000, 60452000 }, { 120904000, 60452000 }, 360.0 },
736 100,
737 { 118872050, 60452000 },
738 true,
739 50 },
740};
741
742
743BOOST_DATA_TEST_CASE( CollidePt, boost::unit_test::data::make( arc_pt_collide_cases ), c )
744{
745 SHAPE_ARC arc( c.m_geom.m_center_point, c.m_geom.m_start_point,
746 EDA_ANGLE( c.m_geom.m_center_angle, DEGREES_T ) );
747
748 // Test a zero width arc (distance should equal the clearance)
749 BOOST_TEST_CONTEXT( "Test Clearance" )
750 {
751 int dist = -1;
752 BOOST_CHECK_EQUAL( arc.Collide( c.m_point, c.m_arc_clearance, &dist ),
753 c.m_exp_result );
754 BOOST_CHECK_EQUAL( dist, c.m_exp_distance );
755 }
756
757 // Test by changing the width of the arc (distance should equal zero)
758 BOOST_TEST_CONTEXT( "Test Width" )
759 {
760 int dist = -1;
761 arc.SetWidth( c.m_arc_clearance * 2 );
762 BOOST_CHECK_EQUAL( arc.Collide( c.m_point, 0, &dist ), c.m_exp_result );
763
764 if( c.m_exp_result )
765 BOOST_CHECK_EQUAL( dist, 0 );
766 else
767 BOOST_CHECK_EQUAL( dist, -1 );
768 }
769}
770
772{
779};
780
781
782static const std::vector<ARC_SEG_COLLIDE_CASE> arc_seg_collide_cases = {
783 { "0 deg ", { { 0, 0 }, { 100, 0 }, 270.0 }, 0, { { 100, 0 }, { 50, 0 } }, true, 0, { 100, 0 } },
784 { "90 deg ", { { 0, 0 }, { 100, 0 }, 270.0 }, 0, { { 0, 100 }, { 0, 50 } }, true, 0, { 0, 100 } },
785 { "180 deg ", { { 0, 0 }, { 100, 0 }, 270.0 }, 0, { { -100, 0 }, { -50, 0 } }, true, 0, { -100, 0 } },
786 { "270 deg ", { { 0, 0 }, { 100, 0 }, 270.0 }, 0, { { 0, -100 }, { 0, -50 } }, true, 0, { 0, -100 } },
787 { "45 deg ", { { 0, 0 }, { 100, 0 }, 270.0 }, 0, { { 71, 71 }, { 35, 35 } }, true, 0, { 70, 70 } },
788 { "-45 deg ", { { 0, 0 }, { 100, 0 }, 270.0 }, 0, { { 71, -71 }, { 35, -35 } }, false, -1, { 0, 0 } },
789 { "seg inside arc start", { { 0, 0 }, { 71, -71 }, 90.0 },
790 10, { { 90, 0 }, { -35, 0 } }, true, 10, { 100, 0 } },
791 { "seg inside arc end", { { 0, 0 }, { 71, -71 }, 90.0 },
792 10, { { -35, 0 }, { 90, 0 } }, true, 10, { 100, 0 } },
793 { "large diameter arc", { { 172367922, 82282076 }, { 162530000, 92120000 }, -45.0 },
794 433300, { { 162096732, 92331236 }, { 162096732, 78253268 } }, true, 433268, { 162530000, 92120000 } },
795 { "upside down collide", { { 26250000, 16520000 }, { 28360000, 16520000 }, 90.0 },
796 0, { { 27545249, 18303444 }, { 27545249, 18114500 } }, true, 0, { 27545249, 18185662 } }
797};
798
799
800BOOST_DATA_TEST_CASE( CollideSeg, boost::unit_test::data::make( arc_seg_collide_cases ), c )
801{
802 SHAPE_ARC arc( c.m_geom.m_center_point, c.m_geom.m_start_point,
803 EDA_ANGLE( c.m_geom.m_center_angle, DEGREES_T ) );
804
805 // Test a zero width arc (distance should equal the clearance)
806 BOOST_TEST_CONTEXT( "Test Clearance" )
807 {
808 int dist = -1;
809 BOOST_CHECK_EQUAL( arc.Collide( c.m_seg, c.m_arc_clearance, &dist ),
810 c.m_exp_result );
811 BOOST_CHECK_EQUAL( dist, c.m_exp_distance );
812 }
813
814 // Test by changing the width of the arc (distance should equal zero)
815 BOOST_TEST_CONTEXT( "Test Width" )
816 {
817 int dist = -1;
818 arc.SetWidth( c.m_arc_clearance * 2 );
819 BOOST_CHECK_EQUAL( arc.Collide( c.m_seg, 0, &dist ), c.m_exp_result );
820
821 if( c.m_exp_result )
822 BOOST_CHECK_EQUAL( dist, 0 );
823 else
824 BOOST_CHECK_EQUAL( dist, -1 );
825 }
826
827 BOOST_TEST_CONTEXT( "Test Collide Point" )
828 {
829 VECTOR2I collide_point;
830 int dist = -1;
831
832 if( c.m_exp_result )
833 {
834 arc.Collide( c.m_seg, c.m_arc_clearance, &dist, &collide_point );
835 BOOST_CHECK_EQUAL( collide_point, c.m_collide_point );
836 }
837 }
838}
839
841{
842 // Coordinates and dimensions in millimeters
845 double m_start_x;
846 double m_start_y;
848 double m_width;
849
851 {
855
856 return arc;
857 }
858};
859
860
862{
867};
868
869
870static const std::vector<ARC_ARC_COLLIDE_CASE> arc_arc_collide_cases = {
871 { "case 1: No intersection",
872 { 73.843527, 74.355869, 71.713528, 72.965869, -76.36664803, 0.2 },
873 { 71.236473, 74.704131, 73.366472, 76.094131, -76.36664803, 0.2 },
874 0,
875 false },
876 { "case 2: No intersection",
877 { 82.542335, 74.825975, 80.413528, 73.435869, -76.4, 0.2 },
878 { 76.491192, 73.839894, 78.619999, 75.23, -76.4, 0.2 },
879 0,
880 false },
881 { "case 3: No intersection",
882 { 89.318807, 74.810106, 87.19, 73.42, -76.4, 0.2 },
883 { 87.045667, 74.632941, 88.826472, 75.794131, -267.9, 0.2 },
884 0,
885 false },
886 { "case 4: Co-centered not intersecting",
887 { 94.665667, 73.772941, 96.446472, 74.934131, -267.9, 0.2 },
888 { 94.665667, 73.772941, 93.6551, 73.025482, -255.5, 0.2 },
889 0,
890 false },
891 { "case 5: Not intersecting, but end points very close",
892 { 72.915251, 80.493054, 73.570159, 81.257692, -260.5, 0.2 },
893 { 73.063537, 82.295989, 71.968628, 81.581351, -255.5, 0.2 },
894 0,
895 false },
896 { "case 6: Coincident centers, colliding due to arc thickness",
897 { 79.279991, 80.67988, 80.3749, 81.394518, -255.5, 0.3 },
898 { 79.279991, 80.67988, 80.3749, 81.694518, -255.5, 0.3 },
899 0,
900 true },
901 { "case 7: Single intersection",
902 { 88.495265, 81.766089, 90.090174, 82.867869, -255.5, 0.2 },
903 { 86.995265, 81.387966, 89.090174, 82.876887, -255.5, 0.2 },
904 0,
905 true },
906 { "case 8: Double intersection",
907 { 96.149734, 81.792126, 94.99, 83.37, -347.2, 0.2 },
908 { 94.857156, 81.240589, 95.91, 83.9, -288.5, 0.2 },
909 0,
910 true },
911 { "case 9: Endpoints within arc width",
912 { 72.915251, 86.493054, 73.970159, 87.257692, -260.5, 0.2 },
913 { 73.063537, 88.295989, 71.968628, 87.581351, -255.5, 0.2 },
914 0,
915 true },
916 { "case 10: Endpoints close, outside, no collision",
917 { 78.915251, 86.393054, 79.970159, 87.157692, 99.5, 0.2 },
918 { 79.063537, 88.295989, 77.968628, 87.581351, -255.5, 0.2 },
919 0,
920 false },
921 { "case 11: Endpoints close, inside, collision due to arc width",
922 { 85.915251, 86.993054, 86.970159, 87.757692, 99.5, 0.2 },
923 { 86.063537, 88.295989, 84.968628, 87.581351, -255.5, 0.2 },
924 0,
925 true },
926 { "case 12: Simulated differential pair length-tuning",
927 { 94.6551, 88.296, 95.6551, 88.296, 90.0, 0.1 },
928 { 94.6551, 88.296, 95.8551, 88.296, 90.0, 0.1 },
929 0.1,
930 false },
931 { "case 13: One arc fully enclosed in other, non-concentric",
932 { 73.77532, 93.413654, 75.70532, 93.883054, 60.0, 0.1 },
933 { 73.86532, 93.393054, 75.86532, 93.393054, 90.0, 0.3 },
934 0,
935 true },
936 { "case 14: One arc fully enclosed in other, concentric",
937 { 79.87532, 93.413654, 81.64532, 94.113054, 60.0, 0.1 },
938 { 79.87532, 93.413654, 81.86532, 93.393054, 90.0, 0.3 },
939 0,
940 true },
941 { "case 15: Arcs separated by clearance",
942 { 303.7615, 149.9252, 303.695968, 149.925237, 90.0262, 0.065 },
943 { 303.6345, 149.2637, 303.634523, 148.85619, 89.9957, 0.065 },
944 0.15,
945 false },
946};
947
948
949BOOST_DATA_TEST_CASE( CollideArc, boost::unit_test::data::make( arc_arc_collide_cases ), c )
950{
951 SHAPE_ARC arc1( c.m_arc1.GenerateArc() );
952 SHAPE_ARC arc2( c.m_arc2.GenerateArc() );
953
954
955 SHAPE_LINE_CHAIN arc1_slc( c.m_arc1.GenerateArc() );
957
958 SHAPE_LINE_CHAIN arc2_slc( c.m_arc2.GenerateArc() );
959 arc2_slc.SetWidth( 0 );
960
961 int actual = 0;
963
964 SHAPE* arc1_sh = &arc1;
968
970 &actual, &location );
971
972 // For arc to chain collisions, we need to re-calculate the clearances because the
973 // SHAPE_LINE_CHAIN is zero width
974 int clearance = pcbIUScale.mmToIU( c.m_clearance ) + ( arc2.GetWidth() / 2 );
975
978
979 clearance = pcbIUScale.mmToIU( c.m_clearance ) + ( arc1.GetWidth() / 2 );
982
983 clearance = ( arc1.GetWidth() / 2 ) + ( arc2.GetWidth() / 2 );
986
991}
992
993
994BOOST_AUTO_TEST_CASE( CollideArcToShapeLineChain )
995{
996 SHAPE_ARC arc( VECTOR2I( 206000000, 140110000 ), VECTOR2I( 201574617, 139229737 ),
997 VECTOR2I( 197822958, 136722959 ), 250000 );
998
999 SHAPE_LINE_CHAIN lc( { VECTOR2I( 159600000, 142500000 ), VECTOR2I( 159600000, 142600000 ),
1000 VECTOR2I( 166400000, 135800000 ), VECTOR2I( 166400000, 111600000 ),
1001 VECTOR2I( 190576804, 111600000 ), VECTOR2I( 192242284, 113265480 ),
1002 VECTOR2I( 192255720, 113265480 ), VECTOR2I( 203682188, 124691948 ),
1003 VECTOR2I( 203682188, 140332188 ), VECTOR2I( 206000000, 142650000 ) },
1004 false );
1005
1006
1007
1008 SHAPE* arc_sh = &arc;
1009 SHAPE* lc_sh = &lc;
1010
1011 BOOST_CHECK_EQUAL( arc_sh->Collide( &lc, 100000 ), true );
1012 BOOST_CHECK_EQUAL( lc_sh->Collide( &arc, 100000 ), true );
1013
1014 SEG seg( VECTOR2I( 203682188, 124691948 ), VECTOR2I( 203682188, 140332188 ) );
1015 BOOST_CHECK_EQUAL( arc.Collide( seg, 0 ), true );
1016}
1017
1018
1019BOOST_AUTO_TEST_CASE( CollideArcToPolygonApproximation )
1020{
1021 SHAPE_ARC arc( VECTOR2I( 73843527, 74355869 ), VECTOR2I( 71713528, 72965869 ),
1022 EDA_ANGLE( -76.36664803, DEGREES_T ), 1000000 );
1023
1024 // Create a polyset approximation from the arc - error outside (simulating the zone filler)
1025 SHAPE_POLY_SET arcBuffer;
1026 int clearance = ( arc.GetWidth() * 3 ) / 2;
1027 int polygonApproximationError = SHAPE_ARC::DefaultAccuracyForPCB();
1028
1029 TransformArcToPolygon( arcBuffer, arc.GetP0(), arc.GetArcMid(), arc.GetP1(),
1030 arc.GetWidth() + 2 * clearance,
1031 polygonApproximationError, ERROR_OUTSIDE );
1032
1033 BOOST_REQUIRE_EQUAL( arcBuffer.OutlineCount(), 1 );
1034 BOOST_CHECK_EQUAL( arcBuffer.HoleCount( 0 ), 0 );
1035
1036 // Make a reasonably large rectangular outline around the arc shape
1037 BOX2I arcbbox = arc.BBox( clearance * 4 );
1038
1039 SHAPE_LINE_CHAIN zoneOutline( { arcbbox.GetPosition(),
1040 arcbbox.GetPosition() + VECTOR2I( arcbbox.GetWidth(), 0 ),
1041 arcbbox.GetEnd(),
1042 arcbbox.GetEnd() - VECTOR2I( arcbbox.GetWidth(), 0 )
1043 },
1044 true );
1045
1046 // Create a synthetic "zone fill" polygon
1047 SHAPE_POLY_SET zoneFill;
1048 zoneFill.AddOutline( zoneOutline );
1049 zoneFill.AddHole( arcBuffer.Outline( 0 ) );
1050 zoneFill.CacheTriangulation( false );
1051
1052 int actual = 0;
1054 int epsilon = polygonApproximationError / 10;
1055
1056 BOOST_CHECK_EQUAL( zoneFill.Collide( &arc, clearance + epsilon, &actual, &location ), true );
1057
1058 BOOST_CHECK_EQUAL( zoneFill.Collide( &arc, clearance - epsilon, &actual, &location ), false );
1059}
1060
1061
1063{
1065};
1066
1067
1077bool ArePolylineEndPointsNearCircle( const SHAPE_LINE_CHAIN& aPolyline, const VECTOR2I& aCentre,
1078 int aRad, int aTolerance )
1079{
1080 std::vector<VECTOR2I> points;
1081
1082 for( int i = 0; i < aPolyline.PointCount(); ++i )
1083 {
1084 points.push_back( aPolyline.CPoint( i ) );
1085 }
1086
1087 return GEOM_TEST::ArePointsNearCircle( points, aCentre, aRad, aTolerance );
1088}
1089
1090
1100bool ArePolylineMidPointsNearCircle( const SHAPE_LINE_CHAIN& aPolyline, const VECTOR2I& aCentre,
1101 int aRad, int aTolerance )
1102{
1103 std::vector<VECTOR2I> points;
1104
1105 for( int i = 0; i < aPolyline.PointCount() - 1; ++i )
1106 {
1107 const VECTOR2I mid_pt = ( aPolyline.CPoint( i ) + aPolyline.CPoint( i + 1 ) ) / 2;
1108 points.push_back( mid_pt );
1109 }
1110
1111 return GEOM_TEST::ArePointsNearCircle( points, aCentre, aRad, aTolerance );
1112}
1113
1114
1115const std::vector<ARC_TO_POLYLINE_CASE> ArcToPolyline_cases{
1116 {
1117 "Zero rad",
1118 {
1119 { 0, 0 },
1120 { 0, 0 },
1121 180,
1122 },
1123 },
1124 {
1125 "Semicircle",
1126 {
1127 { 0, 0 },
1128 { -1000000, 0 },
1129 180,
1130 },
1131 },
1132 {
1133 // check that very small circles don't fall apart and that reverse angles
1134 // work too
1135 "Extremely small semicircle",
1136 {
1137 { 0, 0 },
1138 { -1000, 0 },
1139 -180,
1140 },
1141 },
1142 {
1143 // Make sure it doesn't only work for "easy" angles
1144 "Non-round geometry",
1145 {
1146 { 0, 0 },
1147 { 1234567, 0 },
1148 42.22,
1149 },
1150 },
1151};
1152
1153
1154BOOST_DATA_TEST_CASE( ArcToPolyline, boost::unit_test::data::make( ArcToPolyline_cases ), c )
1155{
1156 const int width = 0;
1157
1158 // Note: do not expect accuracies around 1 to work. We use integers internally so we're
1159 // liable to rounding errors. In PCBNew accuracy defaults to 5000 and we don't recommend
1160 // anything lower than 1000 (for performance reasons).
1161 const int accuracy = 100;
1162 const int epsilon = 1;
1163
1164 const SHAPE_ARC this_arc{ c.m_geom.m_center_point, c.m_geom.m_start_point,
1165 EDA_ANGLE( c.m_geom.m_center_angle, DEGREES_T ), width };
1166
1168
1169 BOOST_TEST_MESSAGE( "Polyline has " << chain.PointCount() << " points" );
1170
1171 // Start point (exactly) where expected
1172 BOOST_CHECK_EQUAL( chain.CPoint( 0 ), c.m_geom.m_start_point );
1173
1174 // End point (exactly) where expected
1176
1177 int radius = ( c.m_geom.m_center_point - c.m_geom.m_start_point ).EuclideanNorm();
1178
1179 // Other points within accuracy + epsilon (for rounding) of where they should be
1181 ( chain )( c.m_geom.m_center_point )( radius )( accuracy + epsilon ) );
1182
1184 ( chain )( c.m_geom.m_center_point )( radius )( accuracy + epsilon ) );
1185}
1186
1187
@ ERROR_OUTSIDE
Definition: approximation.h:33
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:112
constexpr const Vec & GetPosition() const
Definition: box2.h:211
constexpr const Vec GetEnd() const
Definition: box2.h:212
constexpr size_type GetWidth() const
Definition: box2.h:214
double AsDegrees() const
Definition: eda_angle.h:116
Definition: seg.h:42
VECTOR2I A
Definition: seg.h:49
VECTOR2I B
Definition: seg.h:50
EDA_ANGLE GetCentralAngle() const
Get the "central angle" of the arc - this is the angle at the point of the "pie slice".
Definition: shape_arc.cpp:864
const VECTOR2I & GetArcMid() const
Definition: shape_arc.h:118
SEG GetChord() const
Definition: shape_arc.h:242
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
Definition: shape_arc.cpp:413
EDA_ANGLE GetEndAngle() const
Definition: shape_arc.cpp:841
const SHAPE_LINE_CHAIN ConvertToPolyline(int aMaxError=DefaultAccuracyForPCB(), int *aActualError=nullptr) const
Construct a SHAPE_LINE_CHAIN of segments from a given arc.
Definition: shape_arc.cpp:900
int GetWidth() const
Definition: shape_arc.h:210
SHAPE_ARC & ConstructFromStartEndCenter(const VECTOR2I &aStart, const VECTOR2I &aEnd, const VECTOR2I &aCenter, bool aClockwise=false, double aWidth=0)
Constructs this arc from the given start, end and center.
Definition: shape_arc.cpp:213
int m_width
Definition: shape_arc.h:329
const VECTOR2I & GetP1() const
Definition: shape_arc.h:117
bool Collide(const SEG &aSeg, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if the boundary of shape (this) lies closer to the segment aSeg than aClearance,...
Definition: shape_arc.cpp:254
static int DefaultAccuracyForPCB()
Definition: shape_arc.h:278
double GetRadius() const
Definition: shape_arc.cpp:894
EDA_ANGLE GetStartAngle() const
Definition: shape_arc.cpp:833
SHAPE * Clone() const override
Return a dynamically allocated copy of the shape.
Definition: shape_arc.h:86
const VECTOR2I & GetP0() const
Definition: shape_arc.h:116
bool IsSolid() const override
Definition: shape_arc.h:215
const VECTOR2I & GetCenter() const
Definition: shape_arc.cpp:849
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
int PointCount() const
Return the number of points (vertices) in this line chain.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
void SetWidth(int aWidth)
Set the width of all segments in the chain.
Represent a set of closed polygons.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
int HoleCount(int aOutline) const
Returns the number of holes in a given outline.
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
int OutlineCount() const
Return the number of outlines in the set.
An abstract shape on 2D plane.
Definition: shape.h:126
virtual bool Collide(const VECTOR2I &aP, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const
Check if the boundary of shape (this) lies closer to the point aP than aClearance,...
Definition: shape.h:181
static const int MIN_PRECISION_IU
This is the minimum precision for all the points in a shape.
Definition: shape.h:131
void TransformArcToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd, int aWidth, int aError, ERROR_LOC aErrorLoc)
Convert arc to multiple straight segments.
@ DEGREES_T
Definition: eda_angle.h:31
bool ArePointsNearCircle(const std::vector< VECTOR2< T > > &aPoints, const VECTOR2< T > &aCentre, T aRad, T aTol)
Predicate for checking a set of points is within a certain tolerance of a circle.
Numerical test predicates.
@ SH_ARC
circular arc
Definition: shape.h:54
Info to set up an arc by centre, start point and angle.
ARC_START_MID_END m_geom
ARC_CENTRE_PT_ANGLE m_geom
Geom of the arc.
ARC_PROPERTIES m_properties
Expected properties.
int m_width
Arc line width.
double m_center_angle
SHAPE_ARC GenerateArc() const
All properties of an arc (depending on how it's constructed, some of these might be the same as the c...
VECTOR2I m_start_point
VECTOR2I m_end_point
VECTOR2I m_center_point
ARC_CENTRE_PT_ANGLE m_geom
bool m_clockwise
clockwise or anti-clockwise?
ARC_START_END_CENTER m_geom
Geom of the arc.
VECTOR2I m_expected_mid
Expected mid-point of the arc.
ARC_CENTRE_PT_ANGLE m_geom
ARC_START_MID_END m_geom
Geom of the arc.
int m_width
Arc line width.
ARC_PROPERTIES m_properties
Expected properties.
Info to set up an arc by start, mid and end points.
Info to set up an arc by tangent to two segments and a radius.
ARC_CENTRE_PT_ANGLE m_geom
ARC_PROPERTIES m_properties
Expected properties.
ARC_TAN_TAN_RADIUS m_geom
Geom of the arc.
int m_width
Arc line width.
constexpr int mmToIU(double mm) const
Definition: base_units.h:92
A named data-driven test case.
BOOST_DATA_TEST_CASE(ConvertToKicadUnit, boost::unit_test::data::make(altium_to_kicad_unit), input_value, expected_result)
Test conversation from Altium internal units into KiCad internal units.
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_TEST(contains==c.ExpectedContains)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
bool ArePolylineMidPointsNearCircle(const SHAPE_LINE_CHAIN &aPolyline, const VECTOR2I &aCentre, int aRad, int aTolerance)
Predicate for checking a polyline has all the segment mid points on (near) a circle of given centre a...
bool cw
SHAPE_ARC arc2(c.m_arc2.GenerateArc())
VECTOR2I center
bool result_chain_to_chain
const SHAPE_LINE_CHAIN chain
static const std::vector< ARC_PT_COLLIDE_CASE > arc_pt_collide_cases
int radius
static void CheckArcGeom(const SHAPE_ARC &aArc, const ARC_PROPERTIES &aProps, const int aSynErrIU=1)
Check a SHAPE_ARC against a given set of geometric properties.
BOOST_CHECK_PREDICATE(ArePolylineEndPointsNearCircle,(chain)(c.m_geom.m_center_point)(radius)(accuracy+epsilon))
static const std::vector< ARC_SEC_CASE > arc_sec_cases
SHAPE_LINE_CHAIN arc1_slc(c.m_arc1.GenerateArc())
SHAPE * arc1_sh
BOOST_CHECK_EQUAL(this_arc.GetArcMid(), c.m_expected_mid)
static const std::vector< ARC_SME_CASE > arc_sme_cases
const std::vector< ARC_TO_POLYLINE_CASE > ArcToPolyline_cases
SHAPE * arc2_sh
VECTOR2I end
bool ArePolylineEndPointsNearCircle(const SHAPE_LINE_CHAIN &aPolyline, const VECTOR2I &aCentre, int aRad, int aTolerance)
Predicate for checking a polyline has all the points on (near) a circle of given centre and radius.
static const std::vector< ARC_SEG_COLLIDE_CASE > arc_seg_collide_cases
static void CheckArc(const SHAPE_ARC &aArc, const ARC_PROPERTIES &aProps, const int aSynErrIU=1)
Check an arcs geometry and other class functions.
const int epsilon
BOOST_AUTO_TEST_CASE(NullCtor)
Check correct handling of filter strings (as used by WX)
BOOST_TEST_CONTEXT("Test Clearance")
SHAPE_CIRCLE circle(c.m_circle_center, c.m_circle_radius)
int clearance
VECTOR2I location
SHAPE_ARC this_arc
BOOST_TEST_MESSAGE("Polyline has "<< chain.PointCount()<< " points")
static const std::vector< ARC_CICLE_COLLIDE_CASE > arc_circle_collide_cases
int actual
static const std::vector< ARC_CPA_CASE > arc_cases
bool result_arc_to_chain
static const std::vector< ARC_TTR_CASE > arc_ttr_cases
SHAPE * arc2_slc_sh
const int accuracy
SHAPE_LINE_CHAIN arc2_slc(c.m_arc2.GenerateArc())
static const std::vector< ARC_ARC_COLLIDE_CASE > arc_arc_collide_cases
bool result_arc_to_arc
SHAPE * arc1_slc_sh
bool result_chain_to_arc
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:695
VECTOR2< double > VECTOR2D
Definition: vector2d.h:694