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 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
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
39{
53
60
62 {
63 ArcCircle = SHAPE_ARC( VECTOR2I( 183450000, 128360000 ),
64 VECTOR2I( 183850000, 128360000 ),
65 VECTOR2I( 183450000, 128360000 ), 0 );
66
67 Arc0a = SHAPE_ARC( VECTOR2I( 183450000, 128360000 ),
68 VECTOR2I( 183650000, 128560000 ),
69 VECTOR2I( 183850000, 128360000 ), 0 );
70
71 Arc0b = SHAPE_ARC( VECTOR2I( 183850000, 128360000 ),
72 VECTOR2I( 183650000, 128160000 ),
73 VECTOR2I( 183450000, 128360000 ), 0 );
74
75 Arc1 = SHAPE_ARC( VECTOR2I( 183850000, 128360000 ),
76 VECTOR2I( 183638550, 128640305 ),
77 VECTOR2I( 183500000, 129204974 ), 0 );
78
79 Arc2 = SHAPE_ARC( VECTOR2I( 283450000, 228360000 ),
80 VECTOR2I( 283650000, 228560000 ),
81 VECTOR2I( 283850000, 228360000 ), 0 );
82
83 Arc3 = SHAPE_ARC( VECTOR2I( 0, 0 ),
84 VECTOR2I( 24142136, 10000000 ),
85 VECTOR2I( 0, 20000000 ), 0 );
86
88 Circle1Arc.SetClosed( true );
89
92 Circle2Arcs.SetClosed( true );
93
96
99
102
104 DuplicateArcs.Append( Arc1, ARC_HIGH_DEF ); // should add a segment between end of the chain
105 // and new copy of the arc
106
108 ArcAndPoint.Append( VECTOR2I( 233450000, 228360000 ) );
109
112
113 OnePoint.Append( VECTOR2I( 233450000, 228360000 ) );
114
115 TwoPoints.Append( VECTOR2I( 233450000, 228360000 ) );
116 TwoPoints.Append( VECTOR2I( 263450000, 258360000 ) );
117
119 ThreePoints.Append( VECTOR2I( 263450000, 308360000 ) );
120
121 SegAndArcCoincident.Append( VECTOR2I( 0, 20000000 ) );
123 }
124};
125
126
127BOOST_FIXTURE_TEST_SUITE( TestShapeLineChain, SLC_CASES )
128
129
130BOOST_AUTO_TEST_CASE( ClipperConstructorCase1 )
131{
132 // Case of an arc followed by a segment
133 // The clipper path is not in order (on purpose), to simulate the typical return from clipper
134
135 Clipper2Lib::Path64 pathClipper2 = {
136 { { 125663951, 120099260, 24 }, { 125388111, 120170850, 25 }, { 125124975, 120280270, 26 },
137 { 124879705, 120425376, 27 }, { 124657110, 120603322, 28 }, { 124461556, 120810617, 29 },
138 { 124296876, 121043198, 30 }, { 124166301, 121296503, 31 }, { 124072391, 121565564, 32 },
139 { 124016988, 121845106, 33 }, { 124001177, 122129646, 34 }, { 124025270, 122413605, 35 },
140 { 124088794, 122691414, 36 }, { 124190502, 122957625, 37 }, { 124328401, 123207018, 38 },
141 { 124499787, 123434703, 39 }, { 124598846, 123537154, 40 }, { 127171000, 123786000, 4 },
142 { 127287862, 123704439, 5 }, { 127499716, 123513831, 6 }, { 127682866, 123295498, 7 },
143 { 127833720, 123053722, 8 }, { 127949321, 122793242, 9 }, { 128027402, 122519168, 10 },
144 { 128066430, 122236874, 11 }, { 128065642, 121951896, 12 }, { 128025053, 121669823, 13 },
145 { 127945457, 121396185, 14 }, { 127828417, 121136349, 15 }, { 127676227, 120895410, 16 },
146 { 127491873, 120678094, 17 }, { 127278968, 120488661, 18 }, { 127041689, 120330827, 19 },
147 { 126784688, 120207687, 20 }, { 126513005, 120121655, 21 }, { 126231968, 120074419, 22 },
148 { 125947087, 120066905, 23 } }
149 };
150
151 std::vector<CLIPPER_Z_VALUE> z_values = {
152 { { -1, -1 }, 0 }, { { -1, -1 }, 0 }, { { -1, -1 }, 0 }, { { -1, -1 }, 0 },
153 { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 },
154 { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 },
155 { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 },
156 { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 },
157 { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 },
158 { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 },
159 { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 },
160 { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 },
161 { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 },
162 { { 0, -1 }, 0 }
163 };
164
165 std::vector<SHAPE_ARC> arcs = {
166 SHAPE_ARC( { 127171000, 123786000 }, { 126231718, 120077003 }, { 124598846, 123537154 }, 0 )
167 };
168
169 SHAPE_LINE_CHAIN clipper2chain( pathClipper2, z_values, arcs );
170
171 BOOST_CHECK( GEOM_TEST::IsOutlineValid( clipper2chain ) );
172
173 BOOST_CHECK_EQUAL( clipper2chain.PointCount(), 37 );
174
175 BOOST_CHECK_EQUAL( clipper2chain.ArcCount(), 1 );
176
177 BOOST_CHECK_EQUAL( clipper2chain.ShapeCount(), 2 );
178
179 BOOST_CHECK_EQUAL( clipper2chain.IsClosed(), true );
180}
181
182
183BOOST_AUTO_TEST_CASE( ArcToPolyline )
184{
185 SHAPE_LINE_CHAIN base_chain( { VECTOR2I( 0, 0 ), VECTOR2I( 0, 1000 ), VECTOR2I( 1000, 0 ) } );
186
187 SHAPE_LINE_CHAIN chain_insert( {
188 VECTOR2I( 0, 1500 ),
189 VECTOR2I( 1500, 1500 ),
190 VECTOR2I( 1500, 0 ),
191 } );
192
193 SHAPE_LINE_CHAIN arc_insert1( SHAPE_ARC( VECTOR2I( 0, -100 ), VECTOR2I( 0, -200 ), ANGLE_180 ),
194 false, ARC_HIGH_DEF );
195
196 SHAPE_LINE_CHAIN arc_insert2( SHAPE_ARC( VECTOR2I( 0, 500 ), VECTOR2I( 0, 400 ), ANGLE_180 ),
197 false, ARC_HIGH_DEF );
198
199 BOOST_CHECK_EQUAL( base_chain.CShapes().size(), base_chain.CPoints().size() );
200 BOOST_CHECK_EQUAL( arc_insert1.CShapes().size(), arc_insert1.CPoints().size() );
201 BOOST_CHECK_EQUAL( arc_insert2.CShapes().size(), arc_insert2.CPoints().size() );
202
203 BOOST_CHECK( GEOM_TEST::IsOutlineValid( base_chain ) );
204 BOOST_CHECK( GEOM_TEST::IsOutlineValid( arc_insert1 ) );
205 BOOST_CHECK( GEOM_TEST::IsOutlineValid( arc_insert2 ) );
206
207 base_chain.Insert( 0, SHAPE_ARC( VECTOR2I( 0, -100 ), VECTOR2I( 0, -200 ), ANGLE_180 ), ARC_HIGH_DEF );
208 BOOST_CHECK( GEOM_TEST::IsOutlineValid( base_chain ) );
209 BOOST_CHECK_EQUAL( base_chain.CShapes().size(), base_chain.CPoints().size() );
210
211 base_chain.Replace( 0, 2, chain_insert );
212 BOOST_CHECK( GEOM_TEST::IsOutlineValid( base_chain ) );
213 BOOST_CHECK_EQUAL( base_chain.CShapes().size(), base_chain.CPoints().size() );
214}
215
216
217// Similar test to above but with larger coordinates, so we have more than one point per arc
218BOOST_AUTO_TEST_CASE( ArcToPolylineLargeCoords )
219{
220 SHAPE_LINE_CHAIN base_chain( { VECTOR2I( 0, 0 ), VECTOR2I( 0, 100000 ), VECTOR2I( 100000, 0 ) } );
221
222 SHAPE_LINE_CHAIN chain_insert( {
223 VECTOR2I( 0, 1500000 ),
224 VECTOR2I( 1500000, 1500000 ),
225 VECTOR2I( 1500000, 0 ),
226 } );
227
228 base_chain.Append( SHAPE_ARC( VECTOR2I( 200000, 0 ), VECTOR2I( 300000, 100000 ), ANGLE_180 ),
229 ARC_HIGH_DEF );
230
231 BOOST_CHECK( GEOM_TEST::IsOutlineValid( base_chain ) );
232 BOOST_CHECK_EQUAL( base_chain.PointCount(), 11 );
233
234 base_chain.Insert( 9, VECTOR2I( 250000, 0 ) );
235 BOOST_CHECK( GEOM_TEST::IsOutlineValid( base_chain ) );
236 BOOST_CHECK_EQUAL( base_chain.PointCount(), 12 );
237 BOOST_CHECK_EQUAL( base_chain.ArcCount(), 2 ); // Should have two arcs after the split
238
239 base_chain.Replace( 5, 6, chain_insert );
240 BOOST_CHECK( GEOM_TEST::IsOutlineValid( base_chain ) );
241 BOOST_CHECK_EQUAL( base_chain.PointCount(), 13 ); // Adding 3 points, removing 2
242 BOOST_CHECK_EQUAL( base_chain.ArcCount(), 3 ); // Should have three arcs after the split
243
244 base_chain.Replace( 4, 6, VECTOR2I( 550000, 0 ) );
245 BOOST_CHECK( GEOM_TEST::IsOutlineValid( base_chain ) );
246 BOOST_CHECK_EQUAL( base_chain.PointCount(), 11 ); // Adding 1 point, removing 3
247 BOOST_CHECK_EQUAL( base_chain.ArcCount(), 3 ); // Should still have three arcs
248
249 // Test ClearArcs
250 base_chain.SetClosed( true );
251 double areaPriorToArcRemoval = base_chain.Area();
252 base_chain.ClearArcs();
253
254 BOOST_CHECK( GEOM_TEST::IsOutlineValid( base_chain ) );
255 BOOST_CHECK_EQUAL( base_chain.CPoints().size(), base_chain.CShapes().size() );
256 BOOST_CHECK_EQUAL( base_chain.PointCount(), 11 ); // We should have the same number of points
257 BOOST_CHECK_EQUAL( base_chain.ArcCount(), 0 ); // All arcs should have been removed
258 BOOST_CHECK_EQUAL( base_chain.Area(), areaPriorToArcRemoval ); // Area should not have changed
259}
260
261// Test that duplicate point gets removed when line is set to be closed and added where required
262BOOST_AUTO_TEST_CASE( SetClosedDuplicatePoint )
263{
264 // Test from issue #9843
266
267 chain.Append( SHAPE_ARC( { -859598, 2559876 }, { -1632771, 1022403 }, { -3170244, 249230 }, 0 ),
268 ARC_HIGH_DEF );
269
270 chain.Append( SHAPE_ARC( { -3170244, -1657832 }, { -292804, -317564 }, { 1047464, 2559876 }, 0 ),
271 ARC_HIGH_DEF );
272
273 chain.Append( VECTOR2I( -859598, 2559876 ) ); // add point that is equal to first arc start
274
275 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
277
278 // CLOSED CHAIN
279 chain.SetClosed( true );
280 BOOST_CHECK_EQUAL( chain.CPoints().size(), chain.CShapes().size() );
281 BOOST_CHECK_EQUAL( chain.PointCount(), 30 ); // (-1) should have removed coincident points
282 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
283
284 // Special case: arc wrapping around to start (e.g. circle)
285 BOOST_CHECK( GEOM_TEST::IsOutlineValid( Circle2Arcs ) );
286 BOOST_CHECK_EQUAL( Circle2Arcs.IsClosed(), true );
287 BOOST_CHECK_EQUAL( Circle2Arcs.PointCount(), 16 );
288 BOOST_CHECK_EQUAL( Circle2Arcs.IsArcSegment( 15 ), true );
289 BOOST_CHECK_EQUAL( Circle2Arcs.ShapeCount(), 2 );
290 Circle2Arcs.SetClosed( false );
291 BOOST_CHECK( GEOM_TEST::IsOutlineValid( Circle2Arcs ) );
292 BOOST_CHECK_EQUAL( Circle2Arcs.IsClosed(), false );
293 BOOST_CHECK_EQUAL( Circle2Arcs.PointCount(), 17 );
294 BOOST_CHECK_EQUAL( Circle2Arcs.IsArcSegment( 15 ), true );
295 BOOST_CHECK_EQUAL( Circle2Arcs.IsArcSegment( 16 ), false ); // last point doesn't join up
296}
297
299{
300 std::string m_ctx_name;
307};
308
309static const std::vector<CLOSE_TOGGLE_SHAPE_CASE> close_toggle_shape_cases =
310 {
311 { "Circle1Arc", SLC_CASES().Circle1Arc, true, 1, 15, 1, 16 },
312 { "Circle2Arcs", SLC_CASES().Circle2Arcs, true, 2, 16, 2, 17 },
313 { "ArcsCoincident", SLC_CASES().ArcsCoincident, false, 2, 14, 3, 14 },
314 { "ArcsCoincidentClosed", SLC_CASES().ArcsCoincidentClosed, true, 3, 14, 2, 14 },
315 { "ArcsIndependent", SLC_CASES().ArcsIndependent, false, 3, 18, 4, 18 },
316 // SegAndArcCoincident will remove the segment after SetClosed(true) and SetClosed(false)
317 // disable test for now
318 //{ "SegAndArcCoincident", SLC_CASES().SegAndArcCoincident, false, 2, 92, 2, 91 },
319 { "DuplicateArcs", SLC_CASES().DuplicateArcs, false, 4, 20, 5, 20 },
320 { "ArcAndPoint", SLC_CASES().ArcAndPoint, false, 2, 10, 3, 10 },
321 { "ArcsAndSegMixed", SLC_CASES().ArcsAndSegMixed, false, 4, 19, 5, 19 },
322 { "OnePoint", SLC_CASES().OnePoint, false, 0, 1, 0, 1 }, // no shapes
323 { "TwoPoints", SLC_CASES().TwoPoints, false, 1, 2, 2, 2 }, // there and back
324 { "ThreePoints", SLC_CASES().ThreePoints, false, 2, 3, 3, 3 },
325 };
326
327BOOST_AUTO_TEST_CASE( ToggleClosed )
328{
330 {
331 BOOST_TEST_CONTEXT( c.m_ctx_name )
332 {
333 SHAPE_LINE_CHAIN slc_case = c.m_chain; // make a copy to edit
334 BOOST_CHECK( GEOM_TEST::IsOutlineValid( slc_case ) );
335 BOOST_CHECK_EQUAL( slc_case.IsClosed(), c.m_closed );
336 BOOST_CHECK_EQUAL( slc_case.ShapeCount(), c.m_shape_count );
337 BOOST_CHECK_EQUAL( slc_case.PointCount(), c.m_point_count );
338 slc_case.SetClosed( !c.m_closed );
339 BOOST_CHECK( GEOM_TEST::IsOutlineValid( slc_case ) );
340 BOOST_CHECK_EQUAL( slc_case.IsClosed(), !c.m_closed );
341 BOOST_CHECK_EQUAL( slc_case.ShapeCount(), c.m_expected_shape_count );
342 BOOST_CHECK_EQUAL( slc_case.PointCount(), c.m_expected_point_count );
343 slc_case.SetClosed( c.m_closed ); // toggle back to normal
344 BOOST_CHECK( GEOM_TEST::IsOutlineValid( slc_case ) );
345 BOOST_CHECK_EQUAL( slc_case.IsClosed(), c.m_closed );
346 BOOST_CHECK_EQUAL( slc_case.ShapeCount(), c.m_shape_count );
347 BOOST_CHECK_EQUAL( slc_case.PointCount(), c.m_point_count );
348 }
349 }
350}
351
352
353BOOST_AUTO_TEST_CASE( PointInPolygon )
354{
355 SHAPE_LINE_CHAIN outline1( { { 1316455, 913576 }, { 1316455, 901129 }, { 1321102, 901129 },
356 { 1322152, 901191 }, { 1323055, 901365 }, { 1323830, 901639 },
357 { 1324543, 902036 }, { 1325121, 902521 }, { 1325581, 903100 },
358 { 1325914, 903759 }, { 1326120, 904516 }, { 1326193, 905390 },
359 { 1326121, 906253 }, { 1325915, 907005 }, { 1325581, 907667 },
360 { 1325121, 908248 }, { 1324543, 908735 }, { 1323830, 909132 },
361 { 1323055, 909406 }, { 1322153, 909579 }, { 1321102, 909641 },
362 { 1317174, 909641 }, { 1317757, 909027 }, { 1317757, 913576 } } );
363 SHAPE_LINE_CHAIN outline2( { { 1297076, 916244 }, { 1284629, 916244 }, { 1284629, 911597 },
364 { 1284691, 910547 }, { 1284865, 909644 }, { 1285139, 908869 },
365 { 1285536, 908156 }, { 1286021, 907578 }, { 1286600, 907118 },
366 { 1287259, 906785 }, { 1288016, 906579 }, { 1288890, 906506 },
367 { 1289753, 906578 }, { 1290505, 906784 }, { 1291167, 907118 },
368 { 1291748, 907578 }, { 1292235, 908156 }, { 1292632, 908869 },
369 { 1292906, 909644 }, { 1293079, 910546 }, { 1293141, 911597 },
370 { 1293141, 915525 }, { 1292527, 914942 }, { 1297076, 914942 } } );
371
372 // Test a point inside the polygon
373 VECTOR2I point1( 1317757, 909133 );
374 VECTOR2I point2( 1292633, 914942 );
375
376 outline1.SetClosed( true );
377 outline2.SetClosed( true );
378
379 BOOST_CHECK( outline1.PointInside( point1, 0, false ) );
380 BOOST_CHECK( outline2.PointInside( point2, 0, false ) );
381}
382
383// Test that duplicate point gets removed when we call simplify
384BOOST_AUTO_TEST_CASE( SimplifyDuplicatePoint )
385{
387
388 chain.Append( { 100, 100 } );
389 chain.Append( { 100, 100 }, true ); //duplicate point to simplify
390 chain.Append( { 200, 100 } );
391
392 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
394
395 chain.Simplify();
396
397 BOOST_CHECK_EQUAL( chain.CPoints().size(), chain.CShapes().size() );
398 BOOST_CHECK_EQUAL( chain.PointCount(), 2 ); // (-1) should have removed coincident points
399 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
400}
401
402
403// Test that duplicate point gets removed when we call simplify
404BOOST_AUTO_TEST_CASE( SimplifyKeepEndPoint )
405{
407
408 chain.Append( { 114772424, 90949410 } );
409 chain.Append( { 114767360, 90947240 } );
410 chain.Append( { 114772429, 90947228 } );
411 chain.SetClosed( true );
412
413 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
415
416 chain.Simplify();
417
418 BOOST_CHECK_EQUAL( chain.CPoints().size(), chain.CShapes().size() );
420 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
421}
422
423
424BOOST_AUTO_TEST_CASE( SimplifyPNSChain )
425{
427 chain.Append( VECTOR2I( 157527820, 223074385 ) );
428 chain.Append( VECTOR2I( 186541122, 159990156 ) );
429 chain.Append( VECTOR2I( 186528624, 159977658 ) );
430 chain.Append( VECTOR2I( 186528624, 159770550 ) );
431 chain.Append( VECTOR2I( 186528625, 159366691 ) );
432 chain.Append( VECTOR2I( 186541122, 159354195 ) );
433 chain.Append( VECTOR2I( 186541122, 155566877 ) );
434 chain.Append( VECTOR2I( 187291125, 154816872 ) );
435 chain.Append( VECTOR2I( 187291125, 147807837 ) );
436 chain.Append( VECTOR2I( 189301788, 145797175 ) );
437 chain.Append( VECTOR2I( 194451695, 145797175 ) );
438 chain.Append( VECTOR2I( 195021410, 146366890 ) );
439
440 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
442
443 // The chain should be open, so the points should not be simplified
444 // between the begining and the end.
445 chain.Simplify( 10 );
446
448}
449
450
451BOOST_AUTO_TEST_CASE( SimplifyComplexChain )
452{
454
455 // Append points
456 chain.Append( { 130000, 147320 } );
457 chain.Append( { 125730, 147320 } );
458 chain.Append( { 125730, 150630 } );
459 chain.Append( { 128800, 153700 } );
460 chain.Append( { 150300, 153700 } );
461 chain.Append( { 151500, 152500 } );
462 chain.Append( { 151500, 148900 } );
463 chain.Append( { 149920, 147320 } );
464 chain.Append( { 140000, 147320 } );
465
466 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
468
469 // The chain should be open, so the points should not be simplified
470 // between the begining and the end.
471 chain.Simplify();
472
474
475 chain.SetClosed( true );
476 chain.Simplify();
477
479}
480
482{
483 std::string m_ctx_name;
490};
491
492static const std::vector<REMOVE_SHAPE_CASE> remove_shape_cases =
493 {
494 { "Circle1Arc - 1st arc - index on start", SLC_CASES().Circle1Arc, 1, 1, 0, 0, 0 },
495 { "Circle1Arc - 1st arc - index on mid", SLC_CASES().Circle1Arc, 1, 1, 8, 0, 0 },
496 { "Circle1Arc - 1st arc - index on end", SLC_CASES().Circle1Arc, 1, 1, 14, 0, 0 },
497 { "Circle1Arc - 1st arc - index on -1", SLC_CASES().Circle1Arc, 1, 1, -1, 0, 0 },
498 { "Circle1Arc - invalid index", SLC_CASES().Circle1Arc, 1, 1, 15, 1, 1 },
499
500 { "Circle2Arcs - 1st arc - index on start", SLC_CASES().Circle2Arcs, 2, 2, 0, 2, 1 },
501 { "Circle2Arcs - 1st arc - index on mid", SLC_CASES().Circle2Arcs, 2, 2, 3, 2, 1 },
502 { "Circle2Arcs - 1st arc - index on end", SLC_CASES().Circle2Arcs, 2, 2, 7, 2, 1 },
503 { "Circle2Arcs - 2nd arc - index on start", SLC_CASES().Circle2Arcs, 2, 2, 8, 2, 1 },
504 { "Circle2Arcs - 2nd arc - index on mid", SLC_CASES().Circle2Arcs, 2, 2, 11, 2, 1 },
505 { "Circle2Arcs - 2nd arc - index on end", SLC_CASES().Circle2Arcs, 2, 2, 15, 2, 1 },
506 { "Circle2Arcs - 2nd arc - index on -1", SLC_CASES().Circle2Arcs, 2, 2, -1, 2, 1 },
507 { "Circle2Arcs - invalid index", SLC_CASES().Circle2Arcs, 2, 2, 16, 2, 2 },
508
509 { "ArcsCoinc. - 1st arc - idx on start", SLC_CASES().ArcsCoincident, 2, 2, 0, 1, 1 },
510 { "ArcsCoinc. - 1st arc - idx on mid", SLC_CASES().ArcsCoincident, 2, 2, 3, 1, 1 },
511 { "ArcsCoinc. - 1st arc - idx on end", SLC_CASES().ArcsCoincident, 2, 2, 7, 1, 1 },
512 { "ArcsCoinc. - 2nd arc - idx on start", SLC_CASES().ArcsCoincident, 2, 2, 8, 1, 1 },
513 { "ArcsCoinc. - 2nd arc - idx on mid", SLC_CASES().ArcsCoincident, 2, 2, 10, 1, 1 },
514 { "ArcsCoinc. - 2nd arc - idx on end", SLC_CASES().ArcsCoincident, 2, 2, 13, 1, 1 },
515 { "ArcsCoinc. - 2nd arc - idx on -1", SLC_CASES().ArcsCoincident, 2, 2, -1, 1, 1 },
516 { "ArcsCoinc. - invalid idx", SLC_CASES().ArcsCoincident, 2, 2, 14, 2, 2 },
517 { "ArcsCoinc. - 1st arc - idx on start", SLC_CASES().ArcsCoincident, 2, 2, 0, 1, 1 },
518
519 { "A.Co.Closed - 1st arc - idx on start", SLC_CASES().ArcsCoincidentClosed, 3, 2, 1, 2, 1 },
520 { "A.Co.Closed - 1st arc - idx on mid", SLC_CASES().ArcsCoincidentClosed, 3, 2, 3, 2, 1 },
521 { "A.Co.Closed - 1st arc - idx on end", SLC_CASES().ArcsCoincidentClosed, 3, 2, 7, 2, 1 },
522 { "A.Co.Closed - 2nd arc - idx on start", SLC_CASES().ArcsCoincidentClosed, 3, 2, 8, 2, 1 },
523 { "A.Co.Closed - 2nd arc - idx on mid", SLC_CASES().ArcsCoincidentClosed, 3, 2, 10, 2, 1 },
524 { "A.Co.Closed - 2nd arc - idx on end", SLC_CASES().ArcsCoincidentClosed, 3, 2, 13, 2, 1 },
525 { "A.Co.Closed - 2nd arc - idx on -1", SLC_CASES().ArcsCoincidentClosed, 3, 2, -1, 2, 1 },
526 { "A.Co.Closed - invalid idx", SLC_CASES().ArcsCoincidentClosed, 3, 2, 14, 3, 2 },
527
528 { "ArcsIndep. - 1st arc - idx on start", SLC_CASES().ArcsIndependent, 3, 2, 0, 1, 1 },
529 { "ArcsIndep. - 1st arc - idx on mid", SLC_CASES().ArcsIndependent, 3, 2, 3, 1, 1 },
530 { "ArcsIndep. - 1st arc - idx on end", SLC_CASES().ArcsIndependent, 3, 2, 8, 1, 1 },
531 { "ArcsIndep. - 2nd arc - idx on start", SLC_CASES().ArcsIndependent, 3, 2, 9, 1, 1 },
532 { "ArcsIndep. - 2nd arc - idx on mid", SLC_CASES().ArcsIndependent, 3, 2, 12, 1, 1 },
533 { "ArcsIndep. - 2nd arc - idx on end", SLC_CASES().ArcsIndependent, 3, 2, 17, 1, 1 },
534 { "ArcsIndep. - 2nd arc - idx on -1", SLC_CASES().ArcsIndependent, 3, 2, -1, 1, 1 },
535 { "ArcsIndep. - invalid idx", SLC_CASES().ArcsIndependent, 3, 2, 18, 3, 2 },
536
537 { "Dup.Arcs - 1st arc - idx on start", SLC_CASES().DuplicateArcs, 4, 3, 0, 3, 2 },
538 { "Dup.Arcs - 1st arc - idx on mid", SLC_CASES().DuplicateArcs, 4, 3, 3, 3, 2 },
539 { "Dup.Arcs - 1st arc - idx on end", SLC_CASES().DuplicateArcs, 4, 3, 7, 3, 2 },
540 { "Dup.Arcs - 2nd arc - idx on start", SLC_CASES().DuplicateArcs, 4, 3, 8, 3, 2 },
541 { "Dup.Arcs - 2nd arc - idx on mid", SLC_CASES().DuplicateArcs, 4, 3, 10, 3, 2 },
542 { "Dup.Arcs - 2nd arc - idx on end", SLC_CASES().DuplicateArcs, 4, 3, 13, 3, 2 },
543 { "Dup.Arcs - 3rd arc - idx on start", SLC_CASES().DuplicateArcs, 4, 3, 14, 2, 2 },
544 { "Dup.Arcs - 3rd arc - idx on mid", SLC_CASES().DuplicateArcs, 4, 3, 17, 2, 2 },
545 { "Dup.Arcs - 3rd arc - idx on end", SLC_CASES().DuplicateArcs, 4, 3, 19, 2, 2 },
546 { "Dup.Arcs - 3rd arc - idx on -1", SLC_CASES().DuplicateArcs, 4, 3, -1, 2, 2 },
547 { "Dup.Arcs - invalid idx", SLC_CASES().DuplicateArcs, 4, 3, 20, 4, 3 },
548
549 { "Arcs Mixed - 1st arc - idx on start", SLC_CASES().ArcsAndSegMixed, 4, 2, 0, 2, 1 },
550 { "Arcs Mixed - 1st arc - idx on mid", SLC_CASES().ArcsAndSegMixed, 4, 2, 3, 2, 1 },
551 { "Arcs Mixed - 1st arc - idx on end", SLC_CASES().ArcsAndSegMixed, 4, 2, 8, 2, 1 },
552 { "Arcs Mixed - Straight segment", SLC_CASES().ArcsAndSegMixed, 4, 2, 9, 3, 2 },
553 { "Arcs Mixed - 2nd arc - idx on start", SLC_CASES().ArcsAndSegMixed, 4, 2, 10, 2, 1 },
554 { "Arcs Mixed - 2nd arc - idx on mid", SLC_CASES().ArcsAndSegMixed, 4, 2, 14, 2, 1 },
555 { "Arcs Mixed - 2nd arc - idx on end", SLC_CASES().ArcsAndSegMixed, 4, 2, 18, 2, 1 },
556 { "Arcs Mixed - 2nd arc - idx on -1", SLC_CASES().ArcsAndSegMixed, 4, 2, -1, 2, 1 },
557 { "Arcs Mixed - invalid idx", SLC_CASES().ArcsAndSegMixed, 4, 2, 19, 4, 2 }
558 };
559
560
562{
563 for( const REMOVE_SHAPE_CASE& c : remove_shape_cases )
564 {
565 BOOST_TEST_CONTEXT( c.m_ctx_name )
566 {
567 SHAPE_LINE_CHAIN slc_case = c.m_chain; // make a copy to edit
568 BOOST_CHECK_EQUAL( slc_case.ShapeCount(), c.m_shape_count );
569 BOOST_CHECK_EQUAL( slc_case.ArcCount(), c.m_arc_count );
570 BOOST_CHECK_EQUAL( GEOM_TEST::IsOutlineValid( slc_case ), true );
571 slc_case.RemoveShape( c.m_remove_index );
572 BOOST_CHECK_EQUAL( slc_case.ShapeCount(), c.m_expected_shape_count );
573 BOOST_CHECK_EQUAL( slc_case.ArcCount(), c.m_expected_arc_count );
574 BOOST_CHECK_EQUAL( GEOM_TEST::IsOutlineValid( slc_case ), true );
575 }
576 }
577}
578
579
580BOOST_AUTO_TEST_CASE( RemoveShapeAfterSimplify )
581{
582 for( const REMOVE_SHAPE_CASE& c : remove_shape_cases )
583 {
584 BOOST_TEST_CONTEXT( c.m_ctx_name )
585 {
586 SHAPE_LINE_CHAIN slc_case = c.m_chain; // make a copy to edit
587 BOOST_CHECK_EQUAL( GEOM_TEST::IsOutlineValid( slc_case ), true );
588 BOOST_CHECK_EQUAL( slc_case.ShapeCount(), c.m_shape_count );
589 BOOST_CHECK_EQUAL( slc_case.ArcCount(), c.m_arc_count );
590 slc_case.Simplify();
591 BOOST_CHECK_EQUAL( GEOM_TEST::IsOutlineValid( slc_case ), true );
592 BOOST_CHECK_EQUAL( slc_case.ShapeCount(), c.m_shape_count );
593 BOOST_CHECK_EQUAL( slc_case.ArcCount(), c.m_arc_count );
594 slc_case.RemoveShape( c.m_remove_index );
595 BOOST_CHECK_EQUAL( GEOM_TEST::IsOutlineValid( slc_case ), true );
596 BOOST_CHECK_EQUAL( slc_case.ShapeCount(), c.m_expected_shape_count );
597 BOOST_CHECK_EQUAL( slc_case.ArcCount(), c.m_expected_arc_count );
598 }
599 }
600}
601
602
604{
605 BOOST_CHECK_EQUAL( Circle1Arc.ShapeCount(), 1 );
606 BOOST_CHECK_EQUAL( Circle2Arcs.ShapeCount(), 2 );
607 BOOST_CHECK_EQUAL( ArcsCoincident.ShapeCount(), 2 );
608 BOOST_CHECK_EQUAL( ArcsCoincidentClosed.ShapeCount(), 3 );
609 BOOST_CHECK_EQUAL( DuplicateArcs.ShapeCount(), 4 );
610 BOOST_CHECK_EQUAL( ArcAndPoint.ShapeCount(), 2 );
611 BOOST_CHECK_EQUAL( ArcsAndSegMixed.ShapeCount(), 4 );
612 BOOST_CHECK_EQUAL( SegAndArcCoincident.ShapeCount(), 2 );
613 BOOST_CHECK_EQUAL( EmptyChain.ShapeCount(), 0 );
614 BOOST_CHECK_EQUAL( OnePoint.ShapeCount(), 0 );
615 BOOST_CHECK_EQUAL( TwoPoints.ShapeCount(), 1 );
616 BOOST_CHECK_EQUAL( ThreePoints.ShapeCount(), 2 );
617}
618
619
621{
622 BOOST_CHECK_EQUAL( Circle1Arc.NextShape( 0 ), -1 ); //only one arc
623
624 BOOST_CHECK_EQUAL( Circle2Arcs.NextShape( 0 ), 8 ); // next shape "Arc0b"
625 BOOST_CHECK_EQUAL( Circle2Arcs.NextShape( 8 ), -1 ); //no more shapes (last point joins with first, part of arc)
626
627 BOOST_CHECK_EQUAL( ArcsCoincident.NextShape( 0 ), 8 ); // next shape "Arc1"
628 BOOST_CHECK_EQUAL( ArcsCoincident.NextShape( 8 ), -1 ); //no more shapes
629
630 BOOST_CHECK_EQUAL( ArcsCoincidentClosed.NextShape( 0 ), 8 ); // next shape "Arc1"
631 BOOST_CHECK_EQUAL( ArcsCoincidentClosed.NextShape( 8 ), 13 ); //next shape is hidden segment joining last/first
632 BOOST_CHECK_EQUAL( ArcsCoincidentClosed.NextShape( 13 ), -1 ); //no more shapes
633
634 BOOST_CHECK_EQUAL( ArcsIndependent.NextShape( 0 ), 8 ); // next shape straight seg
635 BOOST_CHECK_EQUAL( ArcsIndependent.NextShape( 8 ), 9 ); //next shape second arc
636 BOOST_CHECK_EQUAL( ArcsIndependent.NextShape( 9 ), -1 ); //no more shapes
637
638 BOOST_CHECK_EQUAL( DuplicateArcs.NextShape( 0 ), 8 ); // next shape "Arc1"
639 BOOST_CHECK_EQUAL( DuplicateArcs.NextShape( 8 ), 13 ); // next shape hidden segment joining the 2 duplicate arcs
640 BOOST_CHECK_EQUAL( DuplicateArcs.NextShape( 13 ), 14 ); // next shape "Arc1" (duplicate)
641 BOOST_CHECK_EQUAL( DuplicateArcs.NextShape( 14 ), -1 ); //no more shapes
642
643 BOOST_CHECK_EQUAL( ArcAndPoint.NextShape( 0 ), 8 ); // next shape straight segment (end of arc->point)
644 BOOST_CHECK_EQUAL( ArcAndPoint.NextShape( 8 ), -1 ); //no more shapes
645
646 BOOST_CHECK_EQUAL( ArcsAndSegMixed.NextShape( 0 ), 8 ); // next shape straight segment (end of arc->point)
647 BOOST_CHECK_EQUAL( ArcsAndSegMixed.NextShape( 8 ), 9 ); // next shape straight segment (point->begining of arc)
648 BOOST_CHECK_EQUAL( ArcsAndSegMixed.NextShape( 9 ), 10 ); //next shape second arc
649 BOOST_CHECK_EQUAL( ArcsAndSegMixed.NextShape( 10 ), -1 ); //no more shapes
650 BOOST_CHECK_EQUAL( ArcsAndSegMixed.NextShape( 20 ), -1 ); //invalid indices should still work
651 BOOST_CHECK_EQUAL( ArcsAndSegMixed.NextShape( -50 ), -1 ); //invalid indices should still work
652
653 BOOST_CHECK_EQUAL( SegAndArcCoincident.NextShape( 0 ), 1 ); // next shape Arc3
654 BOOST_CHECK_EQUAL( SegAndArcCoincident.NextShape( 1 ), -1 ); //no more shapes
655
656 BOOST_CHECK_EQUAL( EmptyChain.NextShape( 0 ), -1 );
657 BOOST_CHECK_EQUAL( EmptyChain.NextShape( 1 ), -1 ); //invalid indices should still work
658 BOOST_CHECK_EQUAL( EmptyChain.NextShape( 2 ), -1 ); //invalid indices should still work
659 BOOST_CHECK_EQUAL( EmptyChain.NextShape( -2 ), -1 ); //invalid indices should still work
660
661 BOOST_CHECK_EQUAL( OnePoint.NextShape( 0 ), -1 );
662 BOOST_CHECK_EQUAL( OnePoint.NextShape( -1 ), -1 );
663 BOOST_CHECK_EQUAL( OnePoint.NextShape( 1 ), -1 ); //invalid indices should still work
664 BOOST_CHECK_EQUAL( OnePoint.NextShape( 2 ), -1 ); //invalid indices should still work
665 BOOST_CHECK_EQUAL( OnePoint.NextShape( -2 ), -1 ); //invalid indices should still work
666
667 BOOST_CHECK_EQUAL( TwoPoints.NextShape( 0 ), -1 );
668 BOOST_CHECK_EQUAL( TwoPoints.NextShape( 1 ), -1 );
669 BOOST_CHECK_EQUAL( TwoPoints.NextShape( -1 ), -1 );
670
671 BOOST_CHECK_EQUAL( ThreePoints.NextShape( 0 ), 1 );
672 BOOST_CHECK_EQUAL( ThreePoints.NextShape( 1 ), -1 );
673 BOOST_CHECK_EQUAL( ThreePoints.NextShape( 2 ), -1 );
674 BOOST_CHECK_EQUAL( ThreePoints.NextShape( -1 ), -1 );
675}
676
677
678
680{
681 BOOST_TEST_CONTEXT( "Case 1: Arc mid point nearly collinear" )
682 {
683 SHAPE_ARC arc( VECTOR2I( 100000, 0 ), VECTOR2I( 0, 2499 ), VECTOR2I( -100000, 0 ), 0 );
685 chain.Append( arc, ARC_HIGH_DEF );
686 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
689 BOOST_CHECK_EQUAL( chain.GetPoint( 0 ), VECTOR2I( 100000, 0 ) ); //arc start
690 BOOST_CHECK_EQUAL( chain.GetPoint( 1 ), VECTOR2I( -100000, 0 ) ); //arc end
691 BOOST_CHECK_EQUAL( chain.GetPoint( -1 ), VECTOR2I( -100000, 0 ) ); //arc end
692 }
693
694 BOOST_TEST_CONTEXT( "Case 2: Arc = Large Circle" )
695 {
696 SHAPE_ARC arc( VECTOR2I( 100000, 0 ), VECTOR2I( 0, 0 ), VECTOR2I( 100000, 0 ), 0 );
698 chain.Append( arc, ARC_HIGH_DEF );
699 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
702 BOOST_CHECK_EQUAL( chain.GetPoint( 0 ), VECTOR2I( 100000, 0 ) ); //arc start
703 BOOST_CHECK_EQUAL( chain.GetPoint( 9 ), VECTOR2I( 100000, 0 ) ); //arc end
704 BOOST_CHECK_EQUAL( chain.GetPoint( -1 ), VECTOR2I( 100000, 0 ) ); //arc end
705 }
706
707 BOOST_TEST_CONTEXT( "Case 3: Arc = Small Circle (approximate to point)" )
708 {
709 SHAPE_ARC arc( VECTOR2I( 2499, 0 ), VECTOR2I( 0, 0 ), VECTOR2I( 2499, 0 ), 0 );
711 chain.Append( arc, ARC_HIGH_DEF );
712 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
715 BOOST_CHECK_EQUAL( chain.GetPoint( 0 ), VECTOR2I( 2499, 0 ) ); //arc start
716 }
717
718 BOOST_TEST_CONTEXT( "Case 3: Small Arc (approximate to segment)" )
719 {
720 SHAPE_ARC arc( VECTOR2I( 1767, 0 ), VECTOR2I( 2499, 2499 ), VECTOR2I( 0, 1767 ), 0 );
722 chain.Append( arc, ARC_HIGH_DEF );
723 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
726 BOOST_CHECK_EQUAL( chain.GetPoint( 0 ), VECTOR2I( 1767, 0 ) ); //arc start
727 BOOST_CHECK_EQUAL( chain.GetPoint( 1 ), VECTOR2I( 0, 1767 ) ); //arc end
728 }
729
730 BOOST_TEST_CONTEXT( "Case 4: Arc = null arc (all points coincident)" )
731 {
732 SHAPE_ARC arc( VECTOR2I( 2499, 0 ), VECTOR2I( 2499, 0 ), VECTOR2I( 2499, 0 ), 0 );
734 chain.Append( arc, ARC_HIGH_DEF );
735 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
738 BOOST_CHECK_EQUAL( chain.GetPoint( 0 ), VECTOR2I( 2499, 0 ) ); //arc start
739 }
740
741 BOOST_TEST_CONTEXT( "Case 5: Arc = infinite radius (all points very close)" )
742 {
743 SHAPE_ARC arc( VECTOR2I( 2499, 0 ), VECTOR2I( 2500, 0 ), VECTOR2I( 2501, 0 ), 0 );
745 chain.Append( arc, ARC_HIGH_DEF );
746 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
749 BOOST_CHECK_EQUAL( chain.GetPoint( 0 ), VECTOR2I( 2499, 0 ) ); //arc start
750 BOOST_CHECK_EQUAL( chain.GetPoint( 1 ), VECTOR2I( 2501, 0 ) ); //arc end
751 }
752
753 BOOST_TEST_CONTEXT( "Case 6: Arc = large radius (all points very close)" )
754 {
755 SHAPE_ARC arc( VECTOR2I( -100000, 0 ), VECTOR2I( 0, 1 ), VECTOR2I( 100000, 0 ), 0 );
757 chain.Append( arc, ARC_HIGH_DEF );
758 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
761 BOOST_CHECK_EQUAL( chain.GetPoint( 0 ), VECTOR2I( -100000, 0 ) ); //arc start
762 BOOST_CHECK_EQUAL( chain.GetPoint( 1 ), VECTOR2I( 100000, 0 ) ); //arc end
763 }
764}
765
766
767// Test special case where the last arc in the chain has a shared point with the first arc
768BOOST_AUTO_TEST_CASE( ArcWrappingToStartSharedPoints )
769{
770 // represent a circle with two semicircular arcs
771 SHAPE_ARC arc1( VECTOR2I( 100000, 0 ), VECTOR2I( 0, 100000 ), VECTOR2I( -100000, 0 ), 0 );
772 SHAPE_ARC arc2( VECTOR2I( -100000, 0 ), VECTOR2I( 0, -100000 ), VECTOR2I( 100000, 0 ), 0 );
773
774 // Start a chain with the two arcs
776 chain.Append( arc1, ARC_HIGH_DEF );
779 //BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
780
781 // OPEN CHAIN
782 // Start of the chain is not yet a shared point, so can't be an arc end either
783 BOOST_CHECK_EQUAL( chain.IsSharedPt( 0 ), false );
784 BOOST_CHECK_EQUAL( chain.IsArcEnd( 0 ), false );
785 BOOST_CHECK_EQUAL( chain.IsArcStart( 0 ), true );
786
787 // Index 6 is the shared point between the two arcs in the middle of the chain
788 BOOST_CHECK_EQUAL( chain.IsSharedPt( 6 ), true );
789 BOOST_CHECK_EQUAL( chain.IsArcEnd( 6 ), true );
790 BOOST_CHECK_EQUAL( chain.IsArcStart( 6 ), true );
791
792 // End index is not yet a shared point
793 int endIndex = chain.PointCount() - 1;
794 BOOST_CHECK_EQUAL( chain.IsSharedPt( endIndex ), false );
795 BOOST_CHECK_EQUAL( chain.IsArcEnd( endIndex ), true );
796 BOOST_CHECK_EQUAL( chain.IsArcStart( endIndex ), false );
797
798 for( int i = 0; i < chain.PointCount(); i++ )
799 {
800 BOOST_CHECK_EQUAL( chain.IsPtOnArc( i ), true ); // all points in the chain are arcs
801 }
802
803 // CLOSED CHAIN
804 chain.SetClosed( true );
805 BOOST_CHECK_EQUAL( chain.PointCount(), 12 ); // (-1) should have removed coincident points
806 //BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
807
808 // Start of the chain should be a shared point now, so can't be an arc end either
809 BOOST_CHECK_EQUAL( chain.IsSharedPt( 0 ), true );
810 BOOST_CHECK_EQUAL( chain.IsArcEnd( 0 ), true );
811 BOOST_CHECK_EQUAL( chain.IsArcStart( 0 ), true );
812
813 // Index 6 is the shared point between the two arcs in the middle of the chain
814 BOOST_CHECK_EQUAL( chain.IsSharedPt( 6 ), true );
815 BOOST_CHECK_EQUAL( chain.IsArcEnd( 6 ), true );
816 BOOST_CHECK_EQUAL( chain.IsArcStart( 6 ), true );
817
818 // End index is in the middle of an arc, so not an end point or shared point
819 endIndex = chain.PointCount() - 1;
820 BOOST_CHECK_EQUAL( chain.IsSharedPt( endIndex ), false );
821 BOOST_CHECK_EQUAL( chain.IsArcEnd( endIndex ), false );
822 BOOST_CHECK_EQUAL( chain.IsArcStart( endIndex ), false );
823}
824
825// Test SHAPE_LINE_CHAIN::Split()
827{
828 SEG seg1( VECTOR2I( 0, 100000 ), VECTOR2I( 50000, 0 ) );
829 SEG seg2( VECTOR2I( 200000, 0 ), VECTOR2I( 300000, 0 ) );
830 SHAPE_ARC arc( VECTOR2I( 200000, 0 ), VECTOR2I( 300000, 0 ), ANGLE_180 );
831
832 // Start a chain with 2 points (seg1)
833 SHAPE_LINE_CHAIN chain( { seg1.A, seg1.B } );
835 // Add first arc
836 chain.Append( arc, ARC_HIGH_DEF );
838 // Add two points (seg2)
839 chain.Append( seg2.A );
840 chain.Append( seg2.B );
842 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
843
844 BOOST_TEST_CONTEXT( "Case 1: Point not in the chain" )
845 {
846 SHAPE_LINE_CHAIN chainCopy = chain;
847 BOOST_CHECK_EQUAL( chainCopy.Split( VECTOR2I( 400000, 0 ) ), -1 );
849 BOOST_CHECK_EQUAL( chainCopy.ArcCount(), chain.ArcCount() );
850 }
851
852 BOOST_TEST_CONTEXT( "Case 2: Point close to start of a segment" )
853 {
854 SHAPE_LINE_CHAIN chainCopy = chain;
855 VECTOR2I splitPoint = seg1.A + VECTOR2I( 5, -10 );
856 BOOST_CHECK_EQUAL( chainCopy.Split( splitPoint ), 1 );
857 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chainCopy ) );
858 BOOST_CHECK_EQUAL( chainCopy.GetPoint( 1 ), splitPoint );
859 BOOST_CHECK_EQUAL( chainCopy.PointCount(), chain.PointCount() + 1 ); // new point added
860 BOOST_CHECK_EQUAL( chainCopy.ArcCount(), chain.ArcCount() );
861 }
862
863 BOOST_TEST_CONTEXT( "Case 3: Point exactly on the segment" )
864 {
865 SHAPE_LINE_CHAIN chainCopy = chain;
866 VECTOR2I splitPoint = seg1.B;
867 BOOST_CHECK_EQUAL( chainCopy.Split( splitPoint ), 1 );
868 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chainCopy ) );
869 BOOST_CHECK_EQUAL( chainCopy.GetPoint( 1 ), splitPoint );
871 BOOST_CHECK_EQUAL( chainCopy.ArcCount(), chain.ArcCount() );
872 }
873
874 BOOST_TEST_CONTEXT( "Case 4: Point at start of arc" )
875 {
876 SHAPE_LINE_CHAIN chainCopy = chain;
877 VECTOR2I splitPoint = arc.GetP0();
878 BOOST_CHECK_EQUAL( chainCopy.Split( splitPoint ), 2 );
879 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chainCopy ) );
880 BOOST_CHECK_EQUAL( chainCopy.GetPoint( 2 ), splitPoint );
882 BOOST_CHECK_EQUAL( chainCopy.ArcCount(), chain.ArcCount() );
883 }
884
885 BOOST_TEST_CONTEXT( "Case 5: Point close to start of arc" )
886 {
887 SHAPE_LINE_CHAIN chainCopy = chain;
888 VECTOR2I splitPoint = arc.GetP0() + VECTOR2I( -10, 130 );
889 BOOST_CHECK_EQUAL( chainCopy.Split( splitPoint ), 3 );
890 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chainCopy ) );
891 BOOST_CHECK_EQUAL( chainCopy.GetPoint( 3 ), splitPoint );
892 BOOST_CHECK_EQUAL( chainCopy.IsSharedPt( 3 ), true ); // must be a shared point
893 BOOST_CHECK_EQUAL( chainCopy.PointCount(), chain.PointCount() + 1 ); // new point added
894 BOOST_CHECK_EQUAL( chainCopy.ArcCount(), chain.ArcCount() + 1 ); // new arc should have been created
895 }
896}
897
898
899// Test SHAPE_LINE_CHAIN::Slice()
901{
902 SEG targetSegment( VECTOR2I( 200000, 0 ), VECTOR2I( 300000, 0 ) );
903 SHAPE_ARC firstArc( VECTOR2I( 200000, 0 ), VECTOR2I( 300000, 0 ), ANGLE_180 );
904 SHAPE_ARC secondArc( VECTOR2I( -200000, -200000 ), VECTOR2I( -300000, -100000 ), -ANGLE_180 );
905 int tol = SHAPE_ARC::DefaultAccuracyForPCB(); // Tolerance for arc collisions
906
907 // Start a chain with 3 points
908 SHAPE_LINE_CHAIN chain( { VECTOR2I( 0, 0 ), VECTOR2I( 0, 100000 ), VECTOR2I( 100000, 0 ) } );
910 // Add first arc
911 chain.Append( firstArc, ARC_HIGH_DEF );
913 // Add two points (target segment)
914 chain.Append( targetSegment.A );
915 chain.Append( targetSegment.B );
917 // Add a second arc
918 chain.Append( secondArc, ARC_HIGH_DEF );
920 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
921
925 BOOST_TEST_CONTEXT( "Case 1: Start at arc endpoint, finish middle of arc" )
926 {
927 SHAPE_LINE_CHAIN sliceResult = chain.Slice( 9, 18, ARC_HIGH_DEF );
928 BOOST_CHECK( GEOM_TEST::IsOutlineValid( sliceResult ) );
929
930 BOOST_CHECK_EQUAL( sliceResult.ArcCount(), 1 );
931 SHAPE_ARC expectedSliceArc0;
932 expectedSliceArc0.ConstructFromStartEndCenter( secondArc.GetP0(), chain.GetPoint( 18 ),
933 secondArc.GetCenter(),
934 secondArc.IsClockwise() );
935
936 BOOST_CHECK_EQUAL( sliceResult.Arc( 0 ).GetP0(), expectedSliceArc0.GetP0() ); // equal arc start points
937 BOOST_CHECK( sliceResult.Arc( 0 ).Collide( expectedSliceArc0.GetArcMid(), tol ) );
938 BOOST_CHECK( sliceResult.Arc( 0 ).Collide( expectedSliceArc0.GetP1(), tol ) );
939
940 BOOST_CHECK_EQUAL( sliceResult.PointCount(), 10 );
941 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 0 ), firstArc.GetP1() ); // equal to arc end
942 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 1 ), targetSegment.A );
943 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 2 ), targetSegment.B );
944 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 3 ), expectedSliceArc0.GetP0() ); // equal to arc start
945 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( 3 ), true );
946
947 for( int i = 4; i <= 8; i++ )
948 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( i ), false );
949
950 for( int i = 3; i <= 7; i++ )
951 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( i ), false );
952
953 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( 9 ), true );
954 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 9 ), expectedSliceArc0.GetP1() ); // equal to arc end
955 }
956
960 BOOST_TEST_CONTEXT( "Case 2: Start at middle of an arc, finish at arc startpoint" )
961 {
962 SHAPE_LINE_CHAIN sliceResult = chain.Slice( 5, 12, ARC_HIGH_DEF );
963 BOOST_CHECK( GEOM_TEST::IsOutlineValid( sliceResult ) );
964
965 BOOST_CHECK_EQUAL( sliceResult.ArcCount(), 1 );
966 SHAPE_ARC expectedSliceArc0;
967 expectedSliceArc0.ConstructFromStartEndCenter( chain.GetPoint( 5 ), firstArc.GetP1(),
968 firstArc.GetCenter(),
969 firstArc.IsClockwise() );
970
971 BOOST_CHECK_EQUAL( sliceResult.Arc( 0 ).GetP1(),
972 expectedSliceArc0.GetP1() ); // equal arc end points
973 BOOST_CHECK( sliceResult.Arc( 0 ).Collide( expectedSliceArc0.GetArcMid(), tol ) );
974 BOOST_CHECK( sliceResult.Arc( 0 ).Collide( expectedSliceArc0.GetP0(), tol ) );
975
976 BOOST_CHECK_EQUAL( sliceResult.PointCount(), 8 );
977 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 0 ),
978 expectedSliceArc0.GetP0() ); // equal to arc start
979 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( 0 ), true );
980
981 for( int i = 1; i <= 4; i++ )
982 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( i ), false );
983
984 for( int i = 0; i <= 3; i++ )
985 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( i ), false );
986
987 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( 4 ), true );
988 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 4 ),
989 expectedSliceArc0.GetP1() ); // equal to arc end
990
991 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 5 ), targetSegment.A );
992 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 6 ), targetSegment.B );
993 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 7 ), secondArc.GetP0() );
994 }
995
999 BOOST_TEST_CONTEXT( "Case 3: Full arc, nothing else" )
1000 {
1001 SHAPE_LINE_CHAIN sliceResult = chain.Slice( 3, 9, ARC_HIGH_DEF );
1002 BOOST_CHECK( GEOM_TEST::IsOutlineValid( sliceResult ) );
1003
1004 BOOST_CHECK_EQUAL( sliceResult.ArcCount(), 1 );
1005 SHAPE_ARC sliceArc0 = sliceResult.Arc( 0 );
1006
1007 // Equal arc to original inserted arc
1008 BOOST_CHECK_EQUAL( firstArc.GetP1(), sliceArc0.GetP1() );
1009 BOOST_CHECK_EQUAL( firstArc.GetArcMid(), sliceArc0.GetArcMid() );
1010 BOOST_CHECK_EQUAL( firstArc.GetP1(), sliceArc0.GetP1() );
1011
1012 BOOST_CHECK_EQUAL( sliceResult.PointCount(), 7 );
1013 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 0 ), sliceArc0.GetP0() ); // equal to arc start
1014 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( 0 ), true );
1015
1016 for( int i = 1; i <= 6; i++ )
1017 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( i ), false );
1018
1019 for( int i = 0; i <= 5; i++ )
1020 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( i ), false );
1021
1022 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( 6 ), true );
1023 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 6 ), sliceArc0.GetP1() ); // equal to arc end
1024 }
1025
1029 BOOST_TEST_CONTEXT( "Case 4: Full arc, and straight segments to next arc start" )
1030 {
1031 SHAPE_LINE_CHAIN sliceResult = chain.Slice( 3, 12, ARC_HIGH_DEF );
1032 BOOST_CHECK( GEOM_TEST::IsOutlineValid( sliceResult ) );
1033
1034 BOOST_CHECK_EQUAL( sliceResult.ArcCount(), 1 );
1035 SHAPE_ARC sliceArc0 = sliceResult.Arc( 0 );
1036
1037 // Equal arc to original inserted arc
1038 BOOST_CHECK_EQUAL( firstArc.GetP1(), sliceArc0.GetP1() );
1039 BOOST_CHECK_EQUAL( firstArc.GetArcMid(), sliceArc0.GetArcMid() );
1040 BOOST_CHECK_EQUAL( firstArc.GetP1(), sliceArc0.GetP1() );
1041
1042 BOOST_CHECK_EQUAL( sliceResult.PointCount(), 10 );
1043 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 0 ), sliceArc0.GetP0() ); // equal to arc start
1044 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( 0 ), true );
1045
1046 for( int i = 1; i <= 6; i++ )
1047 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( i ), false );
1048
1049 for( int i = 0; i <= 5; i++ )
1050 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( i ), false );
1051
1052 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( 6 ), true );
1053 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 6 ), sliceArc0.GetP1() ); // equal to arc end
1054
1055 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 7 ), targetSegment.A );
1056 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 8 ), targetSegment.B );
1057 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 9 ), secondArc.GetP0() );
1058 }
1059
1060 BOOST_TEST_CONTEXT( "Case 5: Chain ends in arc and point" )
1061 {
1062 SHAPE_LINE_CHAIN chainCopy = chain;
1063 chainCopy.Append( VECTOR2I( 400000, 400000 ) );
1064
1065 SHAPE_LINE_CHAIN sliceResult = chainCopy.Slice( 11, -1, ARC_HIGH_DEF );
1066 BOOST_CHECK( GEOM_TEST::IsOutlineValid( sliceResult ) );
1067 BOOST_CHECK_EQUAL( sliceResult.GetPoint( -1 ), VECTOR2I( 400000, 400000 ) );
1068 }
1069
1070 BOOST_TEST_CONTEXT( "Case 6: Start to end, chain with one point" )
1071 {
1072 SHAPE_LINE_CHAIN chainCopy = SLC_CASES().OnePoint;
1073
1074 SHAPE_LINE_CHAIN sliceResult = chainCopy.Slice( 0, -1, ARC_HIGH_DEF );
1075 BOOST_CHECK_EQUAL( sliceResult.PointCount(), 1 );
1076 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 0 ), VECTOR2I( 233450000, 228360000 ) );
1077 BOOST_CHECK_EQUAL( sliceResult.GetPoint( -1 ), VECTOR2I( 233450000, 228360000 ) ); // Same as index 0
1078 }
1079
1080 BOOST_TEST_CONTEXT( "Case 7: Start to end, chain with two points" )
1081 {
1082 SHAPE_LINE_CHAIN chainCopy = SLC_CASES().TwoPoints;
1083
1084 SHAPE_LINE_CHAIN sliceResult = chainCopy.Slice( 0, -1, ARC_HIGH_DEF );
1085 BOOST_CHECK_EQUAL( sliceResult.PointCount(), 2 );
1086 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 0 ), VECTOR2I( 233450000, 228360000 ) );
1087 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 1 ), VECTOR2I( 263450000, 258360000 ) );
1088 BOOST_CHECK_EQUAL( sliceResult.GetPoint( -1 ), VECTOR2I( 263450000, 258360000 ) ); // Same as index 1
1089 }
1090
1091 BOOST_TEST_CONTEXT( "Case 8: Full 2nd arc, nothing else" )
1092 {
1093 SHAPE_LINE_CHAIN sliceResult = chain.Slice( 12, 19, ARC_HIGH_DEF );
1094 BOOST_CHECK( GEOM_TEST::IsOutlineValid( sliceResult ) );
1095
1096 BOOST_CHECK_EQUAL( sliceResult.ArcCount(), 1 );
1097 SHAPE_ARC sliceArc0 = sliceResult.Arc( 0 );
1098
1099 // Equal arc to original inserted arc
1100 BOOST_CHECK_EQUAL( secondArc.GetP1(), sliceArc0.GetP1() );
1101 BOOST_CHECK_EQUAL( secondArc.GetArcMid(), sliceArc0.GetArcMid() );
1102 BOOST_CHECK_EQUAL( secondArc.GetP1(), sliceArc0.GetP1() );
1103
1104 BOOST_CHECK_EQUAL( sliceResult.PointCount(), 8 );
1105 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 0 ), sliceArc0.GetP0() ); // equal to arc start
1106 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( 0 ), true );
1107
1108 for( int i = 1; i <= 7; i++ )
1109 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( i ), false );
1110
1111 for( int i = 0; i <= 6; i++ )
1112 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( i ), false );
1113
1114 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( 7 ), true );
1115 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 7 ), sliceArc0.GetP1() ); // equal to arc end
1116 }
1117
1118 BOOST_TEST_CONTEXT( "Case 9: Start at middle of a 2nd arc, finish at end" )
1119 {
1120 SHAPE_LINE_CHAIN sliceResult = chain.Slice( 16, 19, ARC_HIGH_DEF );
1121 BOOST_CHECK( GEOM_TEST::IsOutlineValid( sliceResult ) );
1122
1123 BOOST_CHECK_EQUAL( sliceResult.ArcCount(), 1 );
1124
1125 SHAPE_ARC expectedSliceArc0;
1126 expectedSliceArc0.ConstructFromStartEndCenter( chain.GetPoint( 16 ), secondArc.GetP1(),
1127 secondArc.GetCenter(),
1128 secondArc.IsClockwise() );
1129
1130 BOOST_CHECK_EQUAL( sliceResult.Arc( 0 ).GetP1(),
1131 expectedSliceArc0.GetP1() ); // equal arc end points
1132 BOOST_CHECK( sliceResult.Arc( 0 ).Collide( expectedSliceArc0.GetArcMid(), tol ) );
1133 BOOST_CHECK( sliceResult.Arc( 0 ).Collide( expectedSliceArc0.GetP0(), tol ) );
1134
1135 BOOST_CHECK_EQUAL( sliceResult.PointCount(), 4 );
1136 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 0 ),
1137 expectedSliceArc0.GetP0() ); // equal to arc start
1138 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( 0 ), true );
1139
1140 for( int i = 1; i <= 3; i++ )
1141 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( i ), false );
1142
1143 for( int i = 0; i <= 2; i++ )
1144 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( i ), false );
1145
1146 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( 3 ), true );
1147 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 3 ),
1148 expectedSliceArc0.GetP1() ); // equal to arc end
1149 }
1150
1151 BOOST_TEST_CONTEXT( "Case 10: New chain, start at arc middle, finish at end" )
1152 {
1153 SHAPE_LINE_CHAIN chain10;
1154 chain10.Append( firstArc, ARC_HIGH_DEF );
1155
1156 SHAPE_LINE_CHAIN sliceResult = chain10.Slice( 3, 6, ARC_HIGH_DEF );
1157 BOOST_CHECK( GEOM_TEST::IsOutlineValid( sliceResult ) );
1158
1159 BOOST_CHECK_EQUAL( sliceResult.ArcCount(), 1 );
1160
1161 SHAPE_ARC expectedSliceArc0;
1162 expectedSliceArc0.ConstructFromStartEndCenter( chain10.GetPoint( 3 ), firstArc.GetP1(),
1163 firstArc.GetCenter(),
1164 firstArc.IsClockwise() );
1165
1166 BOOST_CHECK_EQUAL( sliceResult.Arc( 0 ).GetP1(),
1167 expectedSliceArc0.GetP1() ); // equal arc end points
1168 BOOST_CHECK( sliceResult.Arc( 0 ).Collide( expectedSliceArc0.GetArcMid(), tol ) );
1169 BOOST_CHECK( sliceResult.Arc( 0 ).Collide( expectedSliceArc0.GetP0(), tol ) );
1170
1171 BOOST_CHECK_EQUAL( sliceResult.PointCount(), 4 );
1172 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 0 ),
1173 expectedSliceArc0.GetP0() ); // equal to arc start
1174 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( 0 ), true );
1175
1176 for( int i = 1; i <= 3; i++ )
1177 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( i ), false );
1178
1179 for( int i = 0; i <= 2; i++ )
1180 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( i ), false );
1181
1182 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( 3 ), true );
1183 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 3 ),
1184 expectedSliceArc0.GetP1() ); // equal to arc end
1185 }
1186}
1187
1188
1189// Test SHAPE_LINE_CHAIN::NearestPoint( VECTOR2I )
1190BOOST_AUTO_TEST_CASE( NearestPointPt )
1191{
1192 SEG seg1( VECTOR2I( 0, 100000 ), VECTOR2I( 50000, 0 ) );
1193 SEG seg2( VECTOR2I( 200000, 0 ), VECTOR2I( 300000, 0 ) );
1194 SHAPE_ARC arc( VECTOR2I( 200000, 0 ), VECTOR2I( 300000, 0 ), ANGLE_180 );
1195
1196 // Start a chain with 2 points (seg1)
1197 SHAPE_LINE_CHAIN chain( { seg1.A, seg1.B } );
1199 // Add first arc
1200 chain.Append( arc, ARC_HIGH_DEF );
1202 // Add two points (seg2)
1203 chain.Append( seg2.A );
1204 chain.Append( seg2.B );
1206 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
1207
1208 VECTOR2I ptOnArcCloseToStart( 297553, 31697 ); //should be index 3 in chain
1209 VECTOR2I ptOnArcCloseToEnd( 139709, 82983 ); //should be index 6 in chain
1210
1211 BOOST_CHECK_EQUAL( chain.NearestPoint( ptOnArcCloseToStart, true ), ptOnArcCloseToStart );
1212 BOOST_CHECK_EQUAL( chain.NearestPoint( ptOnArcCloseToStart, false ), arc.GetP0() );
1213
1214 BOOST_CHECK_EQUAL( chain.NearestPoint( ptOnArcCloseToEnd, true ), ptOnArcCloseToEnd );
1215 BOOST_CHECK_EQUAL( chain.NearestPoint( ptOnArcCloseToEnd, false ), arc.GetP1() );
1216}
1217
1218
1219// Test SHAPE_LINE_CHAIN::Replace( SHAPE_LINE_CHAIN )
1221{
1222 BOOST_TEST_INFO( "8949 crash" );
1223
1224 std::vector<VECTOR2I> linePts = {
1225 { 206000000, 140110000 }, { 192325020, 140110000 }, { 192325020, 113348216 },
1226 { 192251784, 113274980 }, { 175548216, 113274980 }, { 175474980, 113348216 },
1227 { 175474980, 136694980 }, { 160774511, 121994511 }, { 160774511, 121693501 },
1228 { 160086499, 121005489 }, { 159785489, 121005489 }, { 159594511, 120814511 },
1229 { 160086499, 120814511 }, { 160774511, 120126499 }, { 160774511, 119153501 },
1230 { 160086499, 118465489 }, { 159113501, 118465489 }, { 158425489, 119153501 },
1231 { 158425489, 119645489 }, { 157325020, 118545020 }, { 157325020, 101925020 },
1232 { 208674980, 101925020 }, { 208674980, 145474980 }, { 192325020, 145474980 },
1233 { 192325020, 140110000 }
1234 };
1235
1236 SHAPE_LINE_CHAIN baseChain( linePts, false );
1237 baseChain.SetWidth( 250000 );
1238 BOOST_CHECK_EQUAL( baseChain.PointCount(), linePts.size() );
1239
1240 SHAPE_LINE_CHAIN replaceChain( { VECTOR2I( 192325020, 140110000 ) }, false );
1241 BOOST_CHECK_EQUAL( replaceChain.PointCount(), 1 );
1242
1243 baseChain.Replace( 1, 23, replaceChain );
1244
1245 BOOST_CHECK_EQUAL( baseChain.PointCount(), linePts.size() - ( 23 - 1 ) );
1246
1247 // Replacing the last point in a chain is special-cased
1248 baseChain.Replace( baseChain.PointCount() - 1, baseChain.PointCount() - 1, VECTOR2I( -1, -1 ) );
1249
1250 BOOST_CHECK_EQUAL( baseChain.CLastPoint(), VECTOR2I( -1, -1 ) );
1251}
1252
1253
constexpr int ARC_HIGH_DEF
Definition: base_units.h:129
Definition: seg.h:42
VECTOR2I A
Definition: seg.h:49
VECTOR2I B
Definition: seg.h:50
const VECTOR2I & GetArcMid() const
Definition: shape_arc.h:118
bool IsClockwise() const
Definition: shape_arc.h:318
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
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
const VECTOR2I & GetP0() const
Definition: shape_arc.h:116
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...
bool IsPtOnArc(size_t aPtIndex) const
const SHAPE_ARC & Arc(size_t aArc) const
bool IsClosed() const override
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.
int ShapeCount() const
Return the number of shapes (line segments or arcs) in this line chain.
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.
void Simplify(int aTolerance=0)
Simplify the line chain by removing colinear adjacent segments and duplicate vertices.
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 NearestPoint(const VECTOR2I &aP, bool aAllowInternalShapePoints=true) const
Find a point on the line chain that is closest to point aP.
const SHAPE_LINE_CHAIN Slice(int aStartIndex, int aEndIndex) const
Return a subset of this line chain containing the [start_index, end_index] range of points.
const VECTOR2I & CLastPoint() const
Return the last point in the line chain.
size_t ArcCount() const
void RemoveShape(int aPointIndex)
Remove the shape at the given index from the line chain.
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:415
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.
NOTE: Collision of SHAPE_LINE_CHAIN with arcs is tested in test_shape_arc.cpp.
SHAPE_LINE_CHAIN EmptyChain
SHAPE_LINE_CHAIN Circle1Arc
SHAPE_LINE_CHAIN ArcsCoincident
SHAPE_ARC Arc1
start coincident with Arc0a end
SHAPE_ARC Arc2
Independent arc.
SHAPE_ARC Arc3
Arc with angle >180.
SHAPE_ARC Arc0a
First half of a circle.
SHAPE_LINE_CHAIN DuplicateArcs
SHAPE_LINE_CHAIN Circle2Arcs
SHAPE_LINE_CHAIN ArcsCoincidentClosed
SHAPE_LINE_CHAIN TwoPoints
SHAPE_LINE_CHAIN SegAndArcCoincident
SHAPE_LINE_CHAIN ArcsIndependent
SHAPE_ARC ArcCircle
Full Circle arc.
SHAPE_LINE_CHAIN ThreePoints
SHAPE_LINE_CHAIN ArcAndPoint
SHAPE_LINE_CHAIN ArcsAndSegMixed
SHAPE_LINE_CHAIN OnePoint
SHAPE_ARC Arc0b
Second half of a circle.
BOOST_CHECK_EQUAL(ret, c.m_exp_result)
BOOST_AUTO_TEST_SUITE_END()
SHAPE_ARC arc2(c.m_arc2.GenerateArc())
const SHAPE_LINE_CHAIN chain
BOOST_TEST_CONTEXT("Test Clearance")
static const std::vector< CLOSE_TOGGLE_SHAPE_CASE > close_toggle_shape_cases
BOOST_AUTO_TEST_CASE(ClipperConstructorCase1)
static const std::vector< REMOVE_SHAPE_CASE > remove_shape_cases
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:695