KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_shape_line_chain.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 (C) 2019-2021 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
24#include <geometry/shape_arc.h>
26#include <trigo.h>
27
29#include <qa_utils/numeric.h>
31
32#include "geom_test_utils.h"
33
38BOOST_AUTO_TEST_SUITE( ShapeLineChain )
39
40BOOST_AUTO_TEST_CASE( ArcToPolyline )
41{
42 SHAPE_LINE_CHAIN base_chain( { VECTOR2I( 0, 0 ), VECTOR2I( 0, 1000 ), VECTOR2I( 1000, 0 ) } );
43
44 SHAPE_LINE_CHAIN chain_insert( {
45 VECTOR2I( 0, 1500 ),
46 VECTOR2I( 1500, 1500 ),
47 VECTOR2I( 1500, 0 ),
48 } );
49
50 SHAPE_LINE_CHAIN arc_insert1( SHAPE_ARC( VECTOR2I( 0, -100 ), VECTOR2I( 0, -200 ), ANGLE_180 ) );
51
52 SHAPE_LINE_CHAIN arc_insert2( SHAPE_ARC( VECTOR2I( 0, 500 ), VECTOR2I( 0, 400 ), ANGLE_180 ) );
53
54 BOOST_CHECK_EQUAL( base_chain.CShapes().size(), base_chain.CPoints().size() );
55 BOOST_CHECK_EQUAL( arc_insert1.CShapes().size(), arc_insert1.CPoints().size() );
56 BOOST_CHECK_EQUAL( arc_insert2.CShapes().size(), arc_insert2.CPoints().size() );
57
59 BOOST_CHECK( GEOM_TEST::IsOutlineValid( arc_insert1 ) );
60 BOOST_CHECK( GEOM_TEST::IsOutlineValid( arc_insert2 ) );
61
62 base_chain.Insert( 0, SHAPE_ARC( VECTOR2I( 0, -100 ), VECTOR2I( 0, -200 ), ANGLE_180 ) );
64 BOOST_CHECK_EQUAL( base_chain.CShapes().size(), base_chain.CPoints().size() );
65
66 base_chain.Replace( 0, 2, chain_insert );
68 BOOST_CHECK_EQUAL( base_chain.CShapes().size(), base_chain.CPoints().size() );
69}
70
71
72// Similar test to above but with larger coordinates, so we have more than one point per arc
73BOOST_AUTO_TEST_CASE( ArcToPolylineLargeCoords )
74{
75 SHAPE_LINE_CHAIN base_chain( { VECTOR2I( 0, 0 ), VECTOR2I( 0, 100000 ), VECTOR2I( 100000, 0 ) } );
76
77 SHAPE_LINE_CHAIN chain_insert( {
78 VECTOR2I( 0, 1500000 ),
79 VECTOR2I( 1500000, 1500000 ),
80 VECTOR2I( 1500000, 0 ),
81 } );
82
83 base_chain.Append( SHAPE_ARC( VECTOR2I( 200000, 0 ), VECTOR2I( 300000, 100000 ), ANGLE_180 ) );
84
86 BOOST_CHECK_EQUAL( base_chain.PointCount(), 11 );
87
88 base_chain.Insert( 9, VECTOR2I( 250000, 0 ) );
90 BOOST_CHECK_EQUAL( base_chain.PointCount(), 12 );
91 BOOST_CHECK_EQUAL( base_chain.ArcCount(), 2 ); // Should have two arcs after the split
92
93 base_chain.Replace( 5, 6, chain_insert );
95 BOOST_CHECK_EQUAL( base_chain.PointCount(), 13 ); // Adding 3 points, removing 2
96 BOOST_CHECK_EQUAL( base_chain.ArcCount(), 3 ); // Should have three arcs after the split
97
98 base_chain.Replace( 4, 6, VECTOR2I( 550000, 0 ) );
100 BOOST_CHECK_EQUAL( base_chain.PointCount(), 11 ); // Adding 1 point, removing 3
101 BOOST_CHECK_EQUAL( base_chain.ArcCount(), 3 ); // Should still have three arcs
102
103 // Test ClearArcs
104 base_chain.SetClosed( true );
105 double areaPriorToArcRemoval = base_chain.Area();
106 base_chain.ClearArcs();
107
108 BOOST_CHECK( GEOM_TEST::IsOutlineValid( base_chain ) );
109 BOOST_CHECK_EQUAL( base_chain.CPoints().size(), base_chain.CShapes().size() );
110 BOOST_CHECK_EQUAL( base_chain.PointCount(), 11 ); // We should have the same number of points
111 BOOST_CHECK_EQUAL( base_chain.ArcCount(), 0 ); // All arcs should have been removed
112 BOOST_CHECK_EQUAL( base_chain.Area(), areaPriorToArcRemoval ); // Area should not have changed
113}
114
115// Test that duplicate point gets removed when line is set to be closed
116BOOST_AUTO_TEST_CASE( SetClosedDuplicatePoint )
117{
118 // Test from issue #9843
119 SHAPE_LINE_CHAIN chain;
120
121 chain.Append(
122 SHAPE_ARC( { -859598, 2559876 }, { -1632771, 1022403 }, { -3170244, 249230 }, 0 ) );
123
124 chain.Append(
125 SHAPE_ARC( { -3170244, -1657832 }, { -292804, -317564 }, { 1047464, 2559876 }, 0 ) );
126
127 chain.Append( VECTOR2I( -859598, 2559876 ) ); // add point that is equal to first arc start
128
130 BOOST_CHECK_EQUAL( chain.PointCount(), 31 );
131
132 // CLOSED CHAIN
133 chain.SetClosed( true );
134 BOOST_CHECK_EQUAL( chain.CPoints().size(), chain.CShapes().size() );
135 BOOST_CHECK_EQUAL( chain.PointCount(), 30 ); // (-1) should have removed coincident points
137}
138
139// Test that duplicate point gets removed when we call simplify
140BOOST_AUTO_TEST_CASE( SimplifyDuplicatePoint )
141{
142 SHAPE_LINE_CHAIN chain;
143
144 chain.Append( { 100, 100 } );
145 chain.Append( { 100, 100 }, true ); //duplicate point to simplify
146 chain.Append( { 200, 100 } );
147
149 BOOST_CHECK_EQUAL( chain.PointCount(), 3 );
150
151 chain.Simplify();
152
153 BOOST_CHECK_EQUAL( chain.CPoints().size(), chain.CShapes().size() );
154 BOOST_CHECK_EQUAL( chain.PointCount(), 2 ); // (-1) should have removed coincident points
156}
157
158
159// Test special case where the last arc in the chain has a shared point with the first arc
160BOOST_AUTO_TEST_CASE( ArcWrappingToStartSharedPoints )
161{
162 // represent a circle with two semicircular arcs
163 SHAPE_ARC arc1( VECTOR2I( 100000, 0 ), VECTOR2I( 0, 100000 ), VECTOR2I( -100000, 0 ), 0 );
164 SHAPE_ARC arc2( VECTOR2I( -100000, 0 ), VECTOR2I( 0, -100000 ), VECTOR2I( 100000, 0 ), 0 );
165
166 // Start a chain with the two arcs
167 SHAPE_LINE_CHAIN chain;
168 chain.Append( arc1 );
169 chain.Append( arc2 );
170 BOOST_CHECK_EQUAL( chain.PointCount(), 13 );
171 //BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
172
173 // OPEN CHAIN
174 // Start of the chain is not yet a shared point, so can't be an arc end either
175 BOOST_CHECK_EQUAL( chain.IsSharedPt( 0 ), false );
176 BOOST_CHECK_EQUAL( chain.IsArcEnd( 0 ), false );
177 BOOST_CHECK_EQUAL( chain.IsArcStart( 0 ), true );
178
179 // Index 6 is the shared point between the two arcs in the middle of the chain
180 BOOST_CHECK_EQUAL( chain.IsSharedPt( 6 ), true );
181 BOOST_CHECK_EQUAL( chain.IsArcEnd( 6 ), true );
182 BOOST_CHECK_EQUAL( chain.IsArcStart( 6 ), true );
183
184 // End index is not yet a shared point
185 int endIndex = chain.PointCount() - 1;
186 BOOST_CHECK_EQUAL( chain.IsSharedPt( endIndex ), false );
187 BOOST_CHECK_EQUAL( chain.IsArcEnd( endIndex ), true );
188 BOOST_CHECK_EQUAL( chain.IsArcStart( endIndex ), false );
189
190 for( int i = 0; i < chain.PointCount(); i++ )
191 {
192 BOOST_CHECK_EQUAL( chain.IsPtOnArc( i ), true ); // all points in the chain are arcs
193 }
194
195 // CLOSED CHAIN
196 chain.SetClosed( true );
197 BOOST_CHECK_EQUAL( chain.PointCount(), 12 ); // (-1) should have removed coincident points
198 //BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
199
200 // Start of the chain should be a shared point now, so can't be an arc end either
201 BOOST_CHECK_EQUAL( chain.IsSharedPt( 0 ), true );
202 BOOST_CHECK_EQUAL( chain.IsArcEnd( 0 ), true );
203 BOOST_CHECK_EQUAL( chain.IsArcStart( 0 ), true );
204
205 // Index 6 is the shared point between the two arcs in the middle of the chain
206 BOOST_CHECK_EQUAL( chain.IsSharedPt( 6 ), true );
207 BOOST_CHECK_EQUAL( chain.IsArcEnd( 6 ), true );
208 BOOST_CHECK_EQUAL( chain.IsArcStart( 6 ), true );
209
210 // End index is in the middle of an arc, so not an end point or shared point
211 endIndex = chain.PointCount() - 1;
212 BOOST_CHECK_EQUAL( chain.IsSharedPt( endIndex ), false );
213 BOOST_CHECK_EQUAL( chain.IsArcEnd( endIndex ), false );
214 BOOST_CHECK_EQUAL( chain.IsArcStart( endIndex ), false );
215}
216
217// Test SHAPE_LINE_CHAIN::Split()
219{
220 SEG seg1( VECTOR2I( 0, 100000 ), VECTOR2I( 50000, 0 ) );
221 SEG seg2( VECTOR2I( 200000, 0 ), VECTOR2I( 300000, 0 ) );
222 SHAPE_ARC arc( VECTOR2I( 200000, 0 ), VECTOR2I( 300000, 0 ), ANGLE_180 );
223
224 // Start a chain with 2 points (seg1)
225 SHAPE_LINE_CHAIN chain( { seg1.A, seg1.B } );
226 BOOST_CHECK_EQUAL( chain.PointCount(), 2 );
227 // Add first arc
228 chain.Append( arc );
229 BOOST_CHECK_EQUAL( chain.PointCount(), 9 );
230 // Add two points (seg2)
231 chain.Append( seg2.A );
232 chain.Append( seg2.B );
233 BOOST_CHECK_EQUAL( chain.PointCount(), 11 );
235
236 BOOST_TEST_CONTEXT( "Case 1: Point not in the chain" )
237 {
238 SHAPE_LINE_CHAIN chainCopy = chain;
239 BOOST_CHECK_EQUAL( chainCopy.Split( VECTOR2I( 400000, 0 ) ), -1 );
240 BOOST_CHECK_EQUAL( chainCopy.PointCount(), chain.PointCount() );
241 BOOST_CHECK_EQUAL( chainCopy.ArcCount(), chain.ArcCount() );
242 }
243
244 BOOST_TEST_CONTEXT( "Case 2: Point close to start of a segment" )
245 {
246 SHAPE_LINE_CHAIN chainCopy = chain;
247 VECTOR2I splitPoint = seg1.A + VECTOR2I( 5, -10 );
248 BOOST_CHECK_EQUAL( chainCopy.Split( splitPoint ), 1 );
250 BOOST_CHECK_EQUAL( chainCopy.GetPoint( 1 ), splitPoint );
251 BOOST_CHECK_EQUAL( chainCopy.PointCount(), chain.PointCount() + 1 ); // new point added
252 BOOST_CHECK_EQUAL( chainCopy.ArcCount(), chain.ArcCount() );
253 }
254
255 BOOST_TEST_CONTEXT( "Case 3: Point exactly on the segment" )
256 {
257 SHAPE_LINE_CHAIN chainCopy = chain;
258 VECTOR2I splitPoint = seg1.B;
259 BOOST_CHECK_EQUAL( chainCopy.Split( splitPoint ), 1 );
261 BOOST_CHECK_EQUAL( chainCopy.GetPoint( 1 ), splitPoint );
262 BOOST_CHECK_EQUAL( chainCopy.PointCount(), chain.PointCount() );
263 BOOST_CHECK_EQUAL( chainCopy.ArcCount(), chain.ArcCount() );
264 }
265
266 BOOST_TEST_CONTEXT( "Case 4: Point at start of arc" )
267 {
268 SHAPE_LINE_CHAIN chainCopy = chain;
269 VECTOR2I splitPoint = arc.GetP0();
270 BOOST_CHECK_EQUAL( chainCopy.Split( splitPoint ), 2 );
272 BOOST_CHECK_EQUAL( chainCopy.GetPoint( 2 ), splitPoint );
273 BOOST_CHECK_EQUAL( chainCopy.PointCount(), chain.PointCount() );
274 BOOST_CHECK_EQUAL( chainCopy.ArcCount(), chain.ArcCount() );
275 }
276
277 BOOST_TEST_CONTEXT( "Case 5: Point close to start of arc" )
278 {
279 SHAPE_LINE_CHAIN chainCopy = chain;
280 VECTOR2I splitPoint = arc.GetP0() + VECTOR2I( -10, 130 );
281 BOOST_CHECK_EQUAL( chainCopy.Split( splitPoint ), 3 );
283 BOOST_CHECK_EQUAL( chainCopy.GetPoint( 3 ), splitPoint );
284 BOOST_CHECK_EQUAL( chainCopy.IsSharedPt( 3 ), true ); // must be a shared point
285 BOOST_CHECK_EQUAL( chainCopy.PointCount(), chain.PointCount() + 1 ); // new point added
286 BOOST_CHECK_EQUAL( chainCopy.ArcCount(), chain.ArcCount() + 1 ); // new arc should have been created
287 }
288}
289
290
291// Test SHAPE_LINE_CHAIN::Slice()
293{
294 SEG targetSegment( VECTOR2I( 200000, 0 ), VECTOR2I( 300000, 0 ) );
295 SHAPE_ARC firstArc( VECTOR2I( 200000, 0 ), VECTOR2I( 300000, 0 ), ANGLE_180 );
296 SHAPE_ARC secondArc( VECTOR2I( -200000, -200000 ), VECTOR2I( -300000, -100000 ), -ANGLE_180 );
297 int tol = SHAPE_ARC::DefaultAccuracyForPCB(); // Tolerance for arc collisions
298
299 // Start a chain with 3 points
300 SHAPE_LINE_CHAIN chain( { VECTOR2I( 0, 0 ), VECTOR2I( 0, 100000 ), VECTOR2I( 100000, 0 ) } );
301 BOOST_CHECK_EQUAL( chain.PointCount(), 3 );
302 // Add first arc
303 chain.Append( firstArc );
304 BOOST_CHECK_EQUAL( chain.PointCount(), 10 );
305 // Add two points (target segment)
306 chain.Append( targetSegment.A );
307 chain.Append( targetSegment.B );
308 BOOST_CHECK_EQUAL( chain.PointCount(), 12 );
309 // Add a second arc
310 chain.Append( secondArc );
311 BOOST_CHECK_EQUAL( chain.PointCount(), 20 );
313
317 BOOST_TEST_CONTEXT( "Case 1: Start at arc endpoint, finish middle of arc" )
318 {
319 SHAPE_LINE_CHAIN sliceResult = chain.Slice( 9, 18 );
320 BOOST_CHECK( GEOM_TEST::IsOutlineValid( sliceResult ) );
321
322 BOOST_CHECK_EQUAL( sliceResult.ArcCount(), 1 );
323 SHAPE_ARC sliceArc0 = sliceResult.Arc( 0 );
324 BOOST_CHECK_EQUAL( secondArc.GetP0(), sliceArc0.GetP0() ); // equal arc start points
325 BOOST_CHECK( secondArc.Collide( sliceArc0.GetArcMid(), tol ) );
326 BOOST_CHECK( secondArc.Collide( sliceArc0.GetP1(), tol ) );
327
328 BOOST_CHECK_EQUAL( sliceResult.PointCount(), 10 );
329 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 0 ), firstArc.GetP1() ); // equal to arc end
330 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 1 ), targetSegment.A );
331 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 2 ), targetSegment.B );
332 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 3 ), sliceArc0.GetP0() ); // equal to arc start
333 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( 3 ), true );
334
335 for( int i = 4; i <= 8; i++ )
336 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( i ), false );
337
338 for( int i = 3; i <= 7; i++ )
339 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( i ), false );
340
341 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( 9 ), true );
342 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 9 ), sliceArc0.GetP1() ); // equal to arc end
343 }
344
348 BOOST_TEST_CONTEXT( "Case 2: Start at middle of an arc, finish at arc startpoint" )
349 {
350 SHAPE_LINE_CHAIN sliceResult = chain.Slice( 5, 12 );
351 BOOST_CHECK( GEOM_TEST::IsOutlineValid( sliceResult ) );
352
353 BOOST_CHECK_EQUAL( sliceResult.ArcCount(), 1 );
354 SHAPE_ARC sliceArc0 = sliceResult.Arc( 0 );
355 BOOST_CHECK_EQUAL( firstArc.GetP1(), sliceArc0.GetP1() ); // equal arc end points
356 BOOST_CHECK( firstArc.Collide( sliceArc0.GetArcMid(), tol ) );
357 BOOST_CHECK( firstArc.Collide( sliceArc0.GetP0(), tol ) );
358
359 BOOST_CHECK_EQUAL( sliceResult.PointCount(), 8 );
360 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 0 ), sliceArc0.GetP0() );// equal to arc start
361 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( 0 ), true );
362
363 for( int i = 1; i <= 4; i++ )
364 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( i ), false );
365
366 for( int i = 0; i <= 3; i++ )
367 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( i ), false );
368
369 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( 4 ), true );
370 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 4 ), sliceArc0.GetP1() ); // equal to arc end
371
372 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 5 ), targetSegment.A );
373 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 6 ), targetSegment.B );
374 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 7 ), secondArc.GetP0() );
375 }
376
380 BOOST_TEST_CONTEXT( "Case 3: Full arc, nothing else" )
381 {
382 SHAPE_LINE_CHAIN sliceResult = chain.Slice( 3, 9 );
383 BOOST_CHECK( GEOM_TEST::IsOutlineValid( sliceResult ) );
384
385 BOOST_CHECK_EQUAL( sliceResult.ArcCount(), 1 );
386 SHAPE_ARC sliceArc0 = sliceResult.Arc( 0 );
387
388 // Equal arc to original inserted arc
389 BOOST_CHECK_EQUAL( firstArc.GetP1(), sliceArc0.GetP1() );
390 BOOST_CHECK_EQUAL( firstArc.GetArcMid(), sliceArc0.GetArcMid() );
391 BOOST_CHECK_EQUAL( firstArc.GetP1(), sliceArc0.GetP1() );
392
393 BOOST_CHECK_EQUAL( sliceResult.PointCount(), 7 );
394 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 0 ), sliceArc0.GetP0() ); // equal to arc start
395 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( 0 ), true );
396
397 for( int i = 1; i <= 6; i++ )
398 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( i ), false );
399
400 for( int i = 0; i <= 5; i++ )
401 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( i ), false );
402
403 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( 6 ), true );
404 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 6 ), sliceArc0.GetP1() ); // equal to arc end
405 }
406
410 BOOST_TEST_CONTEXT( "Case 4: Full arc, and straight segments to next arc start" )
411 {
412 SHAPE_LINE_CHAIN sliceResult = chain.Slice( 3, 12 );
413 BOOST_CHECK( GEOM_TEST::IsOutlineValid( sliceResult ) );
414
415 BOOST_CHECK_EQUAL( sliceResult.ArcCount(), 1 );
416 SHAPE_ARC sliceArc0 = sliceResult.Arc( 0 );
417
418 // Equal arc to original inserted arc
419 BOOST_CHECK_EQUAL( firstArc.GetP1(), sliceArc0.GetP1() );
420 BOOST_CHECK_EQUAL( firstArc.GetArcMid(), sliceArc0.GetArcMid() );
421 BOOST_CHECK_EQUAL( firstArc.GetP1(), sliceArc0.GetP1() );
422
423 BOOST_CHECK_EQUAL( sliceResult.PointCount(), 10 );
424 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 0 ), sliceArc0.GetP0() ); // equal to arc start
425 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( 0 ), true );
426
427 for( int i = 1; i <= 6; i++ )
428 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( i ), false );
429
430 for( int i = 0; i <= 5; i++ )
431 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( i ), false );
432
433 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( 6 ), true );
434 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 6 ), sliceArc0.GetP1() ); // equal to arc end
435
436 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 7 ), targetSegment.A );
437 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 8 ), targetSegment.B );
438 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 9 ), secondArc.GetP0() );
439 }
440
441 BOOST_TEST_CONTEXT( "Case 5: Chain ends in arc and point" )
442 {
443 SHAPE_LINE_CHAIN chainCopy = chain;
444 chainCopy.Append( VECTOR2I( 400000, 400000 ) );
445
446 SHAPE_LINE_CHAIN sliceResult = chainCopy.Slice( 11, -1 );
447 BOOST_CHECK_EQUAL( sliceResult.GetPoint( -1 ), VECTOR2I( 400000, 400000 ) );
448 }
449}
450
451
452// Test SHAPE_LINE_CHAIN::NearestPoint( VECTOR2I )
453BOOST_AUTO_TEST_CASE( NearestPointPt )
454{
455 SEG seg1( VECTOR2I( 0, 100000 ), VECTOR2I( 50000, 0 ) );
456 SEG seg2( VECTOR2I( 200000, 0 ), VECTOR2I( 300000, 0 ) );
457 SHAPE_ARC arc( VECTOR2I( 200000, 0 ), VECTOR2I( 300000, 0 ), ANGLE_180 );
458
459 // Start a chain with 2 points (seg1)
460 SHAPE_LINE_CHAIN chain( { seg1.A, seg1.B } );
461 BOOST_CHECK_EQUAL( chain.PointCount(), 2 );
462 // Add first arc
463 chain.Append( arc );
464 BOOST_CHECK_EQUAL( chain.PointCount(), 9 );
465 // Add two points (seg2)
466 chain.Append( seg2.A );
467 chain.Append( seg2.B );
468 BOOST_CHECK_EQUAL( chain.PointCount(), 11 );
470
471 VECTOR2I ptOnArcCloseToStart( 297553, 31697 ); //should be index 3 in chain
472 VECTOR2I ptOnArcCloseToEnd( 139709, 82983 ); //should be index 6 in chain
473
474 BOOST_CHECK_EQUAL( chain.NearestPoint( ptOnArcCloseToStart, true ), ptOnArcCloseToStart );
475 BOOST_CHECK_EQUAL( chain.NearestPoint( ptOnArcCloseToStart, false ), arc.GetP0() );
476
477 BOOST_CHECK_EQUAL( chain.NearestPoint( ptOnArcCloseToEnd, true ), ptOnArcCloseToEnd );
478 BOOST_CHECK_EQUAL( chain.NearestPoint( ptOnArcCloseToEnd, false ), arc.GetP1() );
479}
480
481
482// Test SHAPE_LINE_CHAIN::Replace( SHAPE_LINE_CHAIN )
483BOOST_AUTO_TEST_CASE( ReplaceChain )
484{
485 BOOST_TEST_INFO( "8949 crash" );
486
487 std::vector<VECTOR2I> linePts = {
488 { 206000000, 140110000 }, { 192325020, 140110000 }, { 192325020, 113348216 },
489 { 192251784, 113274980 }, { 175548216, 113274980 }, { 175474980, 113348216 },
490 { 175474980, 136694980 }, { 160774511, 121994511 }, { 160774511, 121693501 },
491 { 160086499, 121005489 }, { 159785489, 121005489 }, { 159594511, 120814511 },
492 { 160086499, 120814511 }, { 160774511, 120126499 }, { 160774511, 119153501 },
493 { 160086499, 118465489 }, { 159113501, 118465489 }, { 158425489, 119153501 },
494 { 158425489, 119645489 }, { 157325020, 118545020 }, { 157325020, 101925020 },
495 { 208674980, 101925020 }, { 208674980, 145474980 }, { 192325020, 145474980 },
496 { 192325020, 140110000 }
497 };
498
499 SHAPE_LINE_CHAIN baseChain( linePts, false );
500 baseChain.SetWidth( 250000 );
501 BOOST_CHECK_EQUAL( baseChain.PointCount(), linePts.size() );
502
503 SHAPE_LINE_CHAIN replaceChain( { VECTOR2I( 192325020, 140110000 ) }, false );
504 BOOST_CHECK_EQUAL( replaceChain.PointCount(), 1 );
505
506 baseChain.Replace( 1, 23, replaceChain );
507
508 BOOST_CHECK_EQUAL( baseChain.PointCount(), linePts.size() - ( 23 - 1 ) );
509
510 // Replacing the last point in a chain is special-cased
511 baseChain.Replace( baseChain.PointCount() - 1, baseChain.PointCount() - 1, VECTOR2I( -1, -1 ) );
512
513 BOOST_CHECK_EQUAL( baseChain.CLastPoint(), VECTOR2I( -1, -1 ) );
514}
515
516
517BOOST_AUTO_TEST_SUITE_END()
Definition: seg.h:42
VECTOR2I A
Definition: seg.h:49
VECTOR2I B
Definition: seg.h:50
const VECTOR2I & GetArcMid() const
Definition: shape_arc.h:114
const VECTOR2I & GetP1() const
Definition: shape_arc.h:113
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:242
static double DefaultAccuracyForPCB()
Definition: shape_arc.h:221
const VECTOR2I & GetP0() const
Definition: shape_arc.h:112
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
bool IsPtOnArc(size_t aPtIndex) const
const SHAPE_ARC & Arc(size_t aArc) const
SHAPE_LINE_CHAIN & Simplify(bool aRemoveColinear=true)
Simplify the line chain by removing colinear adjacent segments and duplicate vertices.
virtual const VECTOR2I GetPoint(int aIndex) const override
int Split(const VECTOR2I &aP, bool aExact=false)
Insert the point aP belonging to one of the our segments, splitting the adjacent segment in two.
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
int PointCount() const
Return the number of points (vertices) in this line chain.
bool IsArcEnd(size_t aIndex) const
void Replace(int aStartIndex, int aEndIndex, const VECTOR2I &aP)
Replace points with indices in range [start_index, end_index] with a single point aP.
const SHAPE_LINE_CHAIN Slice(int aStartIndex, int aEndIndex=-1) const
Return a subset of this line chain containing the [start_index, end_index] range of points.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
const std::vector< std::pair< ssize_t, ssize_t > > & CShapes() const
const VECTOR2I & CLastPoint() const
Return the last point in the line chain.
size_t ArcCount() const
bool IsArcStart(size_t aIndex) const
void SetWidth(int aWidth)
Set the width of all segments in the chain.
bool IsSharedPt(size_t aIndex) const
Test if a point is shared between multiple shapes.
const std::vector< VECTOR2I > & CPoints() const
static constexpr EDA_ANGLE & ANGLE_180
Definition: eda_angle.h:441
bool IsOutlineValid(const SHAPE_LINE_CHAIN &aChain)
Verify that a SHAPE_LINE_CHAIN has been assembled correctly by ensuring that the arc start and end po...
Numerical test predicates.
BOOST_CHECK(box.ClosestPointTo(VECTOR2D(0, 0))==VECTOR2D(1, 2))
Test suite for KiCad math code.
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_AUTO_TEST_CASE(ArcToPolyline)
NOTE: Collision of SHAPE_LINE_CHAIN with arcs is tested in test_shape_arc.cpp.
#define BOOST_TEST_CONTEXT(A)
#define BOOST_TEST_INFO(A)
If HAVE_EXPECTED_FAILURES is defined, this means that boost::unit_test::expected_failures is availabl...
VECTOR2< int > VECTOR2I
Definition: vector2d.h:588