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