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( SimplifyComplexChain )
412{
413 SHAPE_LINE_CHAIN chain;
414
415 // Append points
416 chain.Append( { 130000, 147320 } );
417 chain.Append( { 125730, 147320 } );
418 chain.Append( { 125730, 150630 } );
419 chain.Append( { 128800, 153700 } );
420 chain.Append( { 150300, 153700 } );
421 chain.Append( { 151500, 152500 } );
422 chain.Append( { 151500, 148900 } );
423 chain.Append( { 149920, 147320 } );
424 chain.Append( { 140000, 147320 } );
425
427 BOOST_CHECK_EQUAL( chain.PointCount(), 9 );
428
429 // The chain should be open, so the points should not be simplified
430 // between the begining and the end.
431 chain.Simplify();
432
433 BOOST_CHECK_EQUAL( chain.PointCount(), 9 );
434
435 chain.SetClosed( true );
436 chain.Simplify();
437
438 BOOST_CHECK_EQUAL( chain.PointCount(), 8 );
439}
440
442{
443 std::string m_ctx_name;
450};
451
452static const std::vector<REMOVE_SHAPE_CASE> remove_shape_cases =
453 {
454 { "Circle1Arc - 1st arc - index on start", SLC_CASES().Circle1Arc, 1, 1, 0, 0, 0 },
455 { "Circle1Arc - 1st arc - index on mid", SLC_CASES().Circle1Arc, 1, 1, 8, 0, 0 },
456 { "Circle1Arc - 1st arc - index on end", SLC_CASES().Circle1Arc, 1, 1, 14, 0, 0 },
457 { "Circle1Arc - 1st arc - index on -1", SLC_CASES().Circle1Arc, 1, 1, -1, 0, 0 },
458 { "Circle1Arc - invalid index", SLC_CASES().Circle1Arc, 1, 1, 15, 1, 1 },
459
460 { "Circle2Arcs - 1st arc - index on start", SLC_CASES().Circle2Arcs, 2, 2, 0, 2, 1 },
461 { "Circle2Arcs - 1st arc - index on mid", SLC_CASES().Circle2Arcs, 2, 2, 3, 2, 1 },
462 { "Circle2Arcs - 1st arc - index on end", SLC_CASES().Circle2Arcs, 2, 2, 7, 2, 1 },
463 { "Circle2Arcs - 2nd arc - index on start", SLC_CASES().Circle2Arcs, 2, 2, 8, 2, 1 },
464 { "Circle2Arcs - 2nd arc - index on mid", SLC_CASES().Circle2Arcs, 2, 2, 11, 2, 1 },
465 { "Circle2Arcs - 2nd arc - index on end", SLC_CASES().Circle2Arcs, 2, 2, 15, 2, 1 },
466 { "Circle2Arcs - 2nd arc - index on -1", SLC_CASES().Circle2Arcs, 2, 2, -1, 2, 1 },
467 { "Circle2Arcs - invalid index", SLC_CASES().Circle2Arcs, 2, 2, 16, 2, 2 },
468
469 { "ArcsCoinc. - 1st arc - idx on start", SLC_CASES().ArcsCoincident, 2, 2, 0, 1, 1 },
470 { "ArcsCoinc. - 1st arc - idx on mid", SLC_CASES().ArcsCoincident, 2, 2, 3, 1, 1 },
471 { "ArcsCoinc. - 1st arc - idx on end", SLC_CASES().ArcsCoincident, 2, 2, 7, 1, 1 },
472 { "ArcsCoinc. - 2nd arc - idx on start", SLC_CASES().ArcsCoincident, 2, 2, 8, 1, 1 },
473 { "ArcsCoinc. - 2nd arc - idx on mid", SLC_CASES().ArcsCoincident, 2, 2, 10, 1, 1 },
474 { "ArcsCoinc. - 2nd arc - idx on end", SLC_CASES().ArcsCoincident, 2, 2, 13, 1, 1 },
475 { "ArcsCoinc. - 2nd arc - idx on -1", SLC_CASES().ArcsCoincident, 2, 2, -1, 1, 1 },
476 { "ArcsCoinc. - invalid idx", SLC_CASES().ArcsCoincident, 2, 2, 14, 2, 2 },
477 { "ArcsCoinc. - 1st arc - idx on start", SLC_CASES().ArcsCoincident, 2, 2, 0, 1, 1 },
478
479 { "A.Co.Closed - 1st arc - idx on start", SLC_CASES().ArcsCoincidentClosed, 3, 2, 1, 2, 1 },
480 { "A.Co.Closed - 1st arc - idx on mid", SLC_CASES().ArcsCoincidentClosed, 3, 2, 3, 2, 1 },
481 { "A.Co.Closed - 1st arc - idx on end", SLC_CASES().ArcsCoincidentClosed, 3, 2, 7, 2, 1 },
482 { "A.Co.Closed - 2nd arc - idx on start", SLC_CASES().ArcsCoincidentClosed, 3, 2, 8, 2, 1 },
483 { "A.Co.Closed - 2nd arc - idx on mid", SLC_CASES().ArcsCoincidentClosed, 3, 2, 10, 2, 1 },
484 { "A.Co.Closed - 2nd arc - idx on end", SLC_CASES().ArcsCoincidentClosed, 3, 2, 13, 2, 1 },
485 { "A.Co.Closed - 2nd arc - idx on -1", SLC_CASES().ArcsCoincidentClosed, 3, 2, -1, 2, 1 },
486 { "A.Co.Closed - invalid idx", SLC_CASES().ArcsCoincidentClosed, 3, 2, 14, 3, 2 },
487
488 { "ArcsIndep. - 1st arc - idx on start", SLC_CASES().ArcsIndependent, 3, 2, 0, 1, 1 },
489 { "ArcsIndep. - 1st arc - idx on mid", SLC_CASES().ArcsIndependent, 3, 2, 3, 1, 1 },
490 { "ArcsIndep. - 1st arc - idx on end", SLC_CASES().ArcsIndependent, 3, 2, 8, 1, 1 },
491 { "ArcsIndep. - 2nd arc - idx on start", SLC_CASES().ArcsIndependent, 3, 2, 9, 1, 1 },
492 { "ArcsIndep. - 2nd arc - idx on mid", SLC_CASES().ArcsIndependent, 3, 2, 12, 1, 1 },
493 { "ArcsIndep. - 2nd arc - idx on end", SLC_CASES().ArcsIndependent, 3, 2, 17, 1, 1 },
494 { "ArcsIndep. - 2nd arc - idx on -1", SLC_CASES().ArcsIndependent, 3, 2, -1, 1, 1 },
495 { "ArcsIndep. - invalid idx", SLC_CASES().ArcsIndependent, 3, 2, 18, 3, 2 },
496
497 { "Dup.Arcs - 1st arc - idx on start", SLC_CASES().DuplicateArcs, 4, 3, 0, 3, 2 },
498 { "Dup.Arcs - 1st arc - idx on mid", SLC_CASES().DuplicateArcs, 4, 3, 3, 3, 2 },
499 { "Dup.Arcs - 1st arc - idx on end", SLC_CASES().DuplicateArcs, 4, 3, 7, 3, 2 },
500 { "Dup.Arcs - 2nd arc - idx on start", SLC_CASES().DuplicateArcs, 4, 3, 8, 3, 2 },
501 { "Dup.Arcs - 2nd arc - idx on mid", SLC_CASES().DuplicateArcs, 4, 3, 10, 3, 2 },
502 { "Dup.Arcs - 2nd arc - idx on end", SLC_CASES().DuplicateArcs, 4, 3, 13, 3, 2 },
503 { "Dup.Arcs - 3rd arc - idx on start", SLC_CASES().DuplicateArcs, 4, 3, 14, 2, 2 },
504 { "Dup.Arcs - 3rd arc - idx on mid", SLC_CASES().DuplicateArcs, 4, 3, 17, 2, 2 },
505 { "Dup.Arcs - 3rd arc - idx on end", SLC_CASES().DuplicateArcs, 4, 3, 19, 2, 2 },
506 { "Dup.Arcs - 3rd arc - idx on -1", SLC_CASES().DuplicateArcs, 4, 3, -1, 2, 2 },
507 { "Dup.Arcs - invalid idx", SLC_CASES().DuplicateArcs, 4, 3, 20, 4, 3 },
508
509 { "Arcs Mixed - 1st arc - idx on start", SLC_CASES().ArcsAndSegMixed, 4, 2, 0, 2, 1 },
510 { "Arcs Mixed - 1st arc - idx on mid", SLC_CASES().ArcsAndSegMixed, 4, 2, 3, 2, 1 },
511 { "Arcs Mixed - 1st arc - idx on end", SLC_CASES().ArcsAndSegMixed, 4, 2, 8, 2, 1 },
512 { "Arcs Mixed - Straight segment", SLC_CASES().ArcsAndSegMixed, 4, 2, 9, 3, 2 },
513 { "Arcs Mixed - 2nd arc - idx on start", SLC_CASES().ArcsAndSegMixed, 4, 2, 10, 2, 1 },
514 { "Arcs Mixed - 2nd arc - idx on mid", SLC_CASES().ArcsAndSegMixed, 4, 2, 14, 2, 1 },
515 { "Arcs Mixed - 2nd arc - idx on end", SLC_CASES().ArcsAndSegMixed, 4, 2, 18, 2, 1 },
516 { "Arcs Mixed - 2nd arc - idx on -1", SLC_CASES().ArcsAndSegMixed, 4, 2, -1, 2, 1 },
517 { "Arcs Mixed - invalid idx", SLC_CASES().ArcsAndSegMixed, 4, 2, 19, 4, 2 }
518 };
519
520
522{
523 for( const REMOVE_SHAPE_CASE& c : remove_shape_cases )
524 {
525 BOOST_TEST_CONTEXT( c.m_ctx_name )
526 {
527 SHAPE_LINE_CHAIN slc_case = c.m_chain; // make a copy to edit
528 BOOST_CHECK_EQUAL( slc_case.ShapeCount(), c.m_shape_count );
529 BOOST_CHECK_EQUAL( slc_case.ArcCount(), c.m_arc_count );
530 BOOST_CHECK_EQUAL( GEOM_TEST::IsOutlineValid( slc_case ), true );
531 slc_case.RemoveShape( c.m_remove_index );
532 BOOST_CHECK_EQUAL( slc_case.ShapeCount(), c.m_expected_shape_count );
533 BOOST_CHECK_EQUAL( slc_case.ArcCount(), c.m_expected_arc_count );
534 BOOST_CHECK_EQUAL( GEOM_TEST::IsOutlineValid( slc_case ), true );
535 }
536 }
537}
538
539
540BOOST_AUTO_TEST_CASE( RemoveShapeAfterSimplify )
541{
542 for( const REMOVE_SHAPE_CASE& c : remove_shape_cases )
543 {
544 BOOST_TEST_CONTEXT( c.m_ctx_name )
545 {
546 SHAPE_LINE_CHAIN slc_case = c.m_chain; // make a copy to edit
547 BOOST_CHECK_EQUAL( GEOM_TEST::IsOutlineValid( slc_case ), true );
548 BOOST_CHECK_EQUAL( slc_case.ShapeCount(), c.m_shape_count );
549 BOOST_CHECK_EQUAL( slc_case.ArcCount(), c.m_arc_count );
550 slc_case.Simplify();
551 BOOST_CHECK_EQUAL( GEOM_TEST::IsOutlineValid( slc_case ), true );
552 BOOST_CHECK_EQUAL( slc_case.ShapeCount(), c.m_shape_count );
553 BOOST_CHECK_EQUAL( slc_case.ArcCount(), c.m_arc_count );
554 slc_case.RemoveShape( c.m_remove_index );
555 BOOST_CHECK_EQUAL( GEOM_TEST::IsOutlineValid( slc_case ), true );
556 BOOST_CHECK_EQUAL( slc_case.ShapeCount(), c.m_expected_shape_count );
557 BOOST_CHECK_EQUAL( slc_case.ArcCount(), c.m_expected_arc_count );
558 }
559 }
560}
561
562
564{
565 BOOST_CHECK_EQUAL( Circle1Arc.ShapeCount(), 1 );
566 BOOST_CHECK_EQUAL( Circle2Arcs.ShapeCount(), 2 );
567 BOOST_CHECK_EQUAL( ArcsCoincident.ShapeCount(), 2 );
568 BOOST_CHECK_EQUAL( ArcsCoincidentClosed.ShapeCount(), 3 );
569 BOOST_CHECK_EQUAL( DuplicateArcs.ShapeCount(), 4 );
570 BOOST_CHECK_EQUAL( ArcAndPoint.ShapeCount(), 2 );
571 BOOST_CHECK_EQUAL( ArcsAndSegMixed.ShapeCount(), 4 );
572 BOOST_CHECK_EQUAL( SegAndArcCoincident.ShapeCount(), 2 );
573 BOOST_CHECK_EQUAL( EmptyChain.ShapeCount(), 0 );
574 BOOST_CHECK_EQUAL( OnePoint.ShapeCount(), 0 );
575 BOOST_CHECK_EQUAL( TwoPoints.ShapeCount(), 1 );
576 BOOST_CHECK_EQUAL( ThreePoints.ShapeCount(), 2 );
577}
578
579
581{
582 BOOST_CHECK_EQUAL( Circle1Arc.NextShape( 0 ), -1 ); //only one arc
583
584 BOOST_CHECK_EQUAL( Circle2Arcs.NextShape( 0 ), 8 ); // next shape "Arc0b"
585 BOOST_CHECK_EQUAL( Circle2Arcs.NextShape( 8 ), -1 ); //no more shapes (last point joins with first, part of arc)
586
587 BOOST_CHECK_EQUAL( ArcsCoincident.NextShape( 0 ), 8 ); // next shape "Arc1"
588 BOOST_CHECK_EQUAL( ArcsCoincident.NextShape( 8 ), -1 ); //no more shapes
589
590 BOOST_CHECK_EQUAL( ArcsCoincidentClosed.NextShape( 0 ), 8 ); // next shape "Arc1"
591 BOOST_CHECK_EQUAL( ArcsCoincidentClosed.NextShape( 8 ), 13 ); //next shape is hidden segment joining last/first
592 BOOST_CHECK_EQUAL( ArcsCoincidentClosed.NextShape( 13 ), -1 ); //no more shapes
593
594 BOOST_CHECK_EQUAL( ArcsIndependent.NextShape( 0 ), 8 ); // next shape straight seg
595 BOOST_CHECK_EQUAL( ArcsIndependent.NextShape( 8 ), 9 ); //next shape second arc
596 BOOST_CHECK_EQUAL( ArcsIndependent.NextShape( 9 ), -1 ); //no more shapes
597
598 BOOST_CHECK_EQUAL( DuplicateArcs.NextShape( 0 ), 8 ); // next shape "Arc1"
599 BOOST_CHECK_EQUAL( DuplicateArcs.NextShape( 8 ), 13 ); // next shape hidden segment joining the 2 duplicate arcs
600 BOOST_CHECK_EQUAL( DuplicateArcs.NextShape( 13 ), 14 ); // next shape "Arc1" (duplicate)
601 BOOST_CHECK_EQUAL( DuplicateArcs.NextShape( 14 ), -1 ); //no more shapes
602
603 BOOST_CHECK_EQUAL( ArcAndPoint.NextShape( 0 ), 8 ); // next shape straight segment (end of arc->point)
604 BOOST_CHECK_EQUAL( ArcAndPoint.NextShape( 8 ), -1 ); //no more shapes
605
606 BOOST_CHECK_EQUAL( ArcsAndSegMixed.NextShape( 0 ), 8 ); // next shape straight segment (end of arc->point)
607 BOOST_CHECK_EQUAL( ArcsAndSegMixed.NextShape( 8 ), 9 ); // next shape straight segment (point->begining of arc)
608 BOOST_CHECK_EQUAL( ArcsAndSegMixed.NextShape( 9 ), 10 ); //next shape second arc
609 BOOST_CHECK_EQUAL( ArcsAndSegMixed.NextShape( 10 ), -1 ); //no more shapes
610 BOOST_CHECK_EQUAL( ArcsAndSegMixed.NextShape( 20 ), -1 ); //invalid indices should still work
611 BOOST_CHECK_EQUAL( ArcsAndSegMixed.NextShape( -50 ), -1 ); //invalid indices should still work
612
613 BOOST_CHECK_EQUAL( SegAndArcCoincident.NextShape( 0 ), 1 ); // next shape Arc3
614 BOOST_CHECK_EQUAL( SegAndArcCoincident.NextShape( 1 ), -1 ); //no more shapes
615
616 BOOST_CHECK_EQUAL( EmptyChain.NextShape( 0 ), -1 );
617 BOOST_CHECK_EQUAL( EmptyChain.NextShape( 1 ), -1 ); //invalid indices should still work
618 BOOST_CHECK_EQUAL( EmptyChain.NextShape( 2 ), -1 ); //invalid indices should still work
619 BOOST_CHECK_EQUAL( EmptyChain.NextShape( -2 ), -1 ); //invalid indices should still work
620
621 BOOST_CHECK_EQUAL( OnePoint.NextShape( 0 ), -1 );
622 BOOST_CHECK_EQUAL( OnePoint.NextShape( -1 ), -1 );
623 BOOST_CHECK_EQUAL( OnePoint.NextShape( 1 ), -1 ); //invalid indices should still work
624 BOOST_CHECK_EQUAL( OnePoint.NextShape( 2 ), -1 ); //invalid indices should still work
625 BOOST_CHECK_EQUAL( OnePoint.NextShape( -2 ), -1 ); //invalid indices should still work
626
627 BOOST_CHECK_EQUAL( TwoPoints.NextShape( 0 ), -1 );
628 BOOST_CHECK_EQUAL( TwoPoints.NextShape( 1 ), -1 );
629 BOOST_CHECK_EQUAL( TwoPoints.NextShape( -1 ), -1 );
630
631 BOOST_CHECK_EQUAL( ThreePoints.NextShape( 0 ), 1 );
632 BOOST_CHECK_EQUAL( ThreePoints.NextShape( 1 ), -1 );
633 BOOST_CHECK_EQUAL( ThreePoints.NextShape( 2 ), -1 );
634 BOOST_CHECK_EQUAL( ThreePoints.NextShape( -1 ), -1 );
635}
636
637
638
640{
641 BOOST_TEST_CONTEXT( "Case 1: Arc mid point nearly collinear" )
642 {
643 SHAPE_ARC arc( VECTOR2I( 100000, 0 ), VECTOR2I( 0, 2499 ), VECTOR2I( -100000, 0 ), 0 );
644 SHAPE_LINE_CHAIN chain;
645 chain.Append( arc, 5000 );
647 BOOST_CHECK_EQUAL( chain.ArcCount(), 0 );
648 BOOST_CHECK_EQUAL( chain.PointCount(), 2 );
649 BOOST_CHECK_EQUAL( chain.GetPoint( 0 ), VECTOR2I( 100000, 0 ) ); //arc start
650 BOOST_CHECK_EQUAL( chain.GetPoint( 1 ), VECTOR2I( -100000, 0 ) ); //arc end
651 BOOST_CHECK_EQUAL( chain.GetPoint( -1 ), VECTOR2I( -100000, 0 ) ); //arc end
652 }
653
654 BOOST_TEST_CONTEXT( "Case 2: Arc = Large Circle" )
655 {
656 SHAPE_ARC arc( VECTOR2I( 100000, 0 ), VECTOR2I( 0, 0 ), VECTOR2I( 100000, 0 ), 0 );
657 SHAPE_LINE_CHAIN chain;
658 chain.Append( arc, 5000 );
660 BOOST_CHECK_EQUAL( chain.ArcCount(), 1 );
661 BOOST_CHECK_EQUAL( chain.PointCount(), 10 );
662 BOOST_CHECK_EQUAL( chain.GetPoint( 0 ), VECTOR2I( 100000, 0 ) ); //arc start
663 BOOST_CHECK_EQUAL( chain.GetPoint( 9 ), VECTOR2I( 100000, 0 ) ); //arc end
664 BOOST_CHECK_EQUAL( chain.GetPoint( -1 ), VECTOR2I( 100000, 0 ) ); //arc end
665 }
666
667 BOOST_TEST_CONTEXT( "Case 3: Arc = Small Circle (approximate to point)" )
668 {
669 SHAPE_ARC arc( VECTOR2I( 2499, 0 ), VECTOR2I( 0, 0 ), VECTOR2I( 2499, 0 ), 0 );
670 SHAPE_LINE_CHAIN chain;
671 chain.Append( arc, 5000 );
673 BOOST_CHECK_EQUAL( chain.ArcCount(), 0 );
674 BOOST_CHECK_EQUAL( chain.PointCount(), 1 );
675 BOOST_CHECK_EQUAL( chain.GetPoint( 0 ), VECTOR2I( 2499, 0 ) ); //arc start
676 }
677
678 BOOST_TEST_CONTEXT( "Case 3: Small Arc (approximate to segment)" )
679 {
680 SHAPE_ARC arc( VECTOR2I( 1767, 0 ), VECTOR2I( 2499, 2499 ), VECTOR2I( 0, 1767 ), 0 );
681 SHAPE_LINE_CHAIN chain;
682 chain.Append( arc, 5000 );
684 BOOST_CHECK_EQUAL( chain.ArcCount(), 0 );
685 BOOST_CHECK_EQUAL( chain.PointCount(), 2 );
686 BOOST_CHECK_EQUAL( chain.GetPoint( 0 ), VECTOR2I( 1767, 0 ) ); //arc start
687 BOOST_CHECK_EQUAL( chain.GetPoint( 1 ), VECTOR2I( 0, 1767 ) ); //arc end
688 }
689
690 BOOST_TEST_CONTEXT( "Case 4: Arc = null arc (all points coincident)" )
691 {
692 SHAPE_ARC arc( VECTOR2I( 2499, 0 ), VECTOR2I( 2499, 0 ), VECTOR2I( 2499, 0 ), 0 );
693 SHAPE_LINE_CHAIN chain;
694 chain.Append( arc, 5000 );
696 BOOST_CHECK_EQUAL( chain.ArcCount(), 0 );
697 BOOST_CHECK_EQUAL( chain.PointCount(), 1 );
698 BOOST_CHECK_EQUAL( chain.GetPoint( 0 ), VECTOR2I( 2499, 0 ) ); //arc start
699 }
700
701 BOOST_TEST_CONTEXT( "Case 5: Arc = infinite radius (all points very close)" )
702 {
703 SHAPE_ARC arc( VECTOR2I( 2499, 0 ), VECTOR2I( 2500, 0 ), VECTOR2I( 2501, 0 ), 0 );
704 SHAPE_LINE_CHAIN chain;
705 chain.Append( arc, 5000 );
707 BOOST_CHECK_EQUAL( chain.ArcCount(), 0 );
708 BOOST_CHECK_EQUAL( chain.PointCount(), 2 );
709 BOOST_CHECK_EQUAL( chain.GetPoint( 0 ), VECTOR2I( 2499, 0 ) ); //arc start
710 BOOST_CHECK_EQUAL( chain.GetPoint( 1 ), VECTOR2I( 2501, 0 ) ); //arc end
711 }
712
713 BOOST_TEST_CONTEXT( "Case 6: Arc = large radius (all points very close)" )
714 {
715 SHAPE_ARC arc( VECTOR2I( -100000, 0 ), VECTOR2I( 0, 1 ), VECTOR2I( 100000, 0 ), 0 );
716 SHAPE_LINE_CHAIN chain;
717 chain.Append( arc, 5000 );
719 BOOST_CHECK_EQUAL( chain.ArcCount(), 0 );
720 BOOST_CHECK_EQUAL( chain.PointCount(), 2 );
721 BOOST_CHECK_EQUAL( chain.GetPoint( 0 ), VECTOR2I( -100000, 0 ) ); //arc start
722 BOOST_CHECK_EQUAL( chain.GetPoint( 1 ), VECTOR2I( 100000, 0 ) ); //arc end
723 }
724}
725
726
727// Test special case where the last arc in the chain has a shared point with the first arc
728BOOST_AUTO_TEST_CASE( ArcWrappingToStartSharedPoints )
729{
730 // represent a circle with two semicircular arcs
731 SHAPE_ARC arc1( VECTOR2I( 100000, 0 ), VECTOR2I( 0, 100000 ), VECTOR2I( -100000, 0 ), 0 );
732 SHAPE_ARC arc2( VECTOR2I( -100000, 0 ), VECTOR2I( 0, -100000 ), VECTOR2I( 100000, 0 ), 0 );
733
734 // Start a chain with the two arcs
735 SHAPE_LINE_CHAIN chain;
736 chain.Append( arc1 );
737 chain.Append( arc2 );
738 BOOST_CHECK_EQUAL( chain.PointCount(), 13 );
739 //BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
740
741 // OPEN CHAIN
742 // Start of the chain is not yet a shared point, so can't be an arc end either
743 BOOST_CHECK_EQUAL( chain.IsSharedPt( 0 ), false );
744 BOOST_CHECK_EQUAL( chain.IsArcEnd( 0 ), false );
745 BOOST_CHECK_EQUAL( chain.IsArcStart( 0 ), true );
746
747 // Index 6 is the shared point between the two arcs in the middle of the chain
748 BOOST_CHECK_EQUAL( chain.IsSharedPt( 6 ), true );
749 BOOST_CHECK_EQUAL( chain.IsArcEnd( 6 ), true );
750 BOOST_CHECK_EQUAL( chain.IsArcStart( 6 ), true );
751
752 // End index is not yet a shared point
753 int endIndex = chain.PointCount() - 1;
754 BOOST_CHECK_EQUAL( chain.IsSharedPt( endIndex ), false );
755 BOOST_CHECK_EQUAL( chain.IsArcEnd( endIndex ), true );
756 BOOST_CHECK_EQUAL( chain.IsArcStart( endIndex ), false );
757
758 for( int i = 0; i < chain.PointCount(); i++ )
759 {
760 BOOST_CHECK_EQUAL( chain.IsPtOnArc( i ), true ); // all points in the chain are arcs
761 }
762
763 // CLOSED CHAIN
764 chain.SetClosed( true );
765 BOOST_CHECK_EQUAL( chain.PointCount(), 12 ); // (-1) should have removed coincident points
766 //BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
767
768 // Start of the chain should be a shared point now, so can't be an arc end either
769 BOOST_CHECK_EQUAL( chain.IsSharedPt( 0 ), true );
770 BOOST_CHECK_EQUAL( chain.IsArcEnd( 0 ), true );
771 BOOST_CHECK_EQUAL( chain.IsArcStart( 0 ), true );
772
773 // Index 6 is the shared point between the two arcs in the middle of the chain
774 BOOST_CHECK_EQUAL( chain.IsSharedPt( 6 ), true );
775 BOOST_CHECK_EQUAL( chain.IsArcEnd( 6 ), true );
776 BOOST_CHECK_EQUAL( chain.IsArcStart( 6 ), true );
777
778 // End index is in the middle of an arc, so not an end point or shared point
779 endIndex = chain.PointCount() - 1;
780 BOOST_CHECK_EQUAL( chain.IsSharedPt( endIndex ), false );
781 BOOST_CHECK_EQUAL( chain.IsArcEnd( endIndex ), false );
782 BOOST_CHECK_EQUAL( chain.IsArcStart( endIndex ), false );
783}
784
785// Test SHAPE_LINE_CHAIN::Split()
787{
788 SEG seg1( VECTOR2I( 0, 100000 ), VECTOR2I( 50000, 0 ) );
789 SEG seg2( VECTOR2I( 200000, 0 ), VECTOR2I( 300000, 0 ) );
790 SHAPE_ARC arc( VECTOR2I( 200000, 0 ), VECTOR2I( 300000, 0 ), ANGLE_180 );
791
792 // Start a chain with 2 points (seg1)
793 SHAPE_LINE_CHAIN chain( { seg1.A, seg1.B } );
794 BOOST_CHECK_EQUAL( chain.PointCount(), 2 );
795 // Add first arc
796 chain.Append( arc );
797 BOOST_CHECK_EQUAL( chain.PointCount(), 9 );
798 // Add two points (seg2)
799 chain.Append( seg2.A );
800 chain.Append( seg2.B );
801 BOOST_CHECK_EQUAL( chain.PointCount(), 11 );
803
804 BOOST_TEST_CONTEXT( "Case 1: Point not in the chain" )
805 {
806 SHAPE_LINE_CHAIN chainCopy = chain;
807 BOOST_CHECK_EQUAL( chainCopy.Split( VECTOR2I( 400000, 0 ) ), -1 );
808 BOOST_CHECK_EQUAL( chainCopy.PointCount(), chain.PointCount() );
809 BOOST_CHECK_EQUAL( chainCopy.ArcCount(), chain.ArcCount() );
810 }
811
812 BOOST_TEST_CONTEXT( "Case 2: Point close to start of a segment" )
813 {
814 SHAPE_LINE_CHAIN chainCopy = chain;
815 VECTOR2I splitPoint = seg1.A + VECTOR2I( 5, -10 );
816 BOOST_CHECK_EQUAL( chainCopy.Split( splitPoint ), 1 );
818 BOOST_CHECK_EQUAL( chainCopy.GetPoint( 1 ), splitPoint );
819 BOOST_CHECK_EQUAL( chainCopy.PointCount(), chain.PointCount() + 1 ); // new point added
820 BOOST_CHECK_EQUAL( chainCopy.ArcCount(), chain.ArcCount() );
821 }
822
823 BOOST_TEST_CONTEXT( "Case 3: Point exactly on the segment" )
824 {
825 SHAPE_LINE_CHAIN chainCopy = chain;
826 VECTOR2I splitPoint = seg1.B;
827 BOOST_CHECK_EQUAL( chainCopy.Split( splitPoint ), 1 );
829 BOOST_CHECK_EQUAL( chainCopy.GetPoint( 1 ), splitPoint );
830 BOOST_CHECK_EQUAL( chainCopy.PointCount(), chain.PointCount() );
831 BOOST_CHECK_EQUAL( chainCopy.ArcCount(), chain.ArcCount() );
832 }
833
834 BOOST_TEST_CONTEXT( "Case 4: Point at start of arc" )
835 {
836 SHAPE_LINE_CHAIN chainCopy = chain;
837 VECTOR2I splitPoint = arc.GetP0();
838 BOOST_CHECK_EQUAL( chainCopy.Split( splitPoint ), 2 );
840 BOOST_CHECK_EQUAL( chainCopy.GetPoint( 2 ), splitPoint );
841 BOOST_CHECK_EQUAL( chainCopy.PointCount(), chain.PointCount() );
842 BOOST_CHECK_EQUAL( chainCopy.ArcCount(), chain.ArcCount() );
843 }
844
845 BOOST_TEST_CONTEXT( "Case 5: Point close to start of arc" )
846 {
847 SHAPE_LINE_CHAIN chainCopy = chain;
848 VECTOR2I splitPoint = arc.GetP0() + VECTOR2I( -10, 130 );
849 BOOST_CHECK_EQUAL( chainCopy.Split( splitPoint ), 3 );
851 BOOST_CHECK_EQUAL( chainCopy.GetPoint( 3 ), splitPoint );
852 BOOST_CHECK_EQUAL( chainCopy.IsSharedPt( 3 ), true ); // must be a shared point
853 BOOST_CHECK_EQUAL( chainCopy.PointCount(), chain.PointCount() + 1 ); // new point added
854 BOOST_CHECK_EQUAL( chainCopy.ArcCount(), chain.ArcCount() + 1 ); // new arc should have been created
855 }
856}
857
858
859// Test SHAPE_LINE_CHAIN::Slice()
861{
862 SEG targetSegment( VECTOR2I( 200000, 0 ), VECTOR2I( 300000, 0 ) );
863 SHAPE_ARC firstArc( VECTOR2I( 200000, 0 ), VECTOR2I( 300000, 0 ), ANGLE_180 );
864 SHAPE_ARC secondArc( VECTOR2I( -200000, -200000 ), VECTOR2I( -300000, -100000 ), -ANGLE_180 );
865 int tol = SHAPE_ARC::DefaultAccuracyForPCB(); // Tolerance for arc collisions
866
867 // Start a chain with 3 points
868 SHAPE_LINE_CHAIN chain( { VECTOR2I( 0, 0 ), VECTOR2I( 0, 100000 ), VECTOR2I( 100000, 0 ) } );
869 BOOST_CHECK_EQUAL( chain.PointCount(), 3 );
870 // Add first arc
871 chain.Append( firstArc );
872 BOOST_CHECK_EQUAL( chain.PointCount(), 10 );
873 // Add two points (target segment)
874 chain.Append( targetSegment.A );
875 chain.Append( targetSegment.B );
876 BOOST_CHECK_EQUAL( chain.PointCount(), 12 );
877 // Add a second arc
878 chain.Append( secondArc );
879 BOOST_CHECK_EQUAL( chain.PointCount(), 20 );
881
885 BOOST_TEST_CONTEXT( "Case 1: Start at arc endpoint, finish middle of arc" )
886 {
887 SHAPE_LINE_CHAIN sliceResult = chain.Slice( 9, 18 );
888 BOOST_CHECK( GEOM_TEST::IsOutlineValid( sliceResult ) );
889
890 BOOST_CHECK_EQUAL( sliceResult.ArcCount(), 1 );
891 SHAPE_ARC expectedSliceArc0;
892 expectedSliceArc0.ConstructFromStartEndCenter( secondArc.GetP0(), chain.GetPoint( 18 ),
893 secondArc.GetCenter(),
894 secondArc.IsClockwise() );
895
896 BOOST_CHECK_EQUAL( sliceResult.Arc( 0 ).GetP0(), expectedSliceArc0.GetP0() ); // equal arc start points
897 BOOST_CHECK( sliceResult.Arc( 0 ).Collide( expectedSliceArc0.GetArcMid(), tol ) );
898 BOOST_CHECK( sliceResult.Arc( 0 ).Collide( expectedSliceArc0.GetP1(), tol ) );
899
900 BOOST_CHECK_EQUAL( sliceResult.PointCount(), 10 );
901 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 0 ), firstArc.GetP1() ); // equal to arc end
902 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 1 ), targetSegment.A );
903 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 2 ), targetSegment.B );
904 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 3 ), expectedSliceArc0.GetP0() ); // equal to arc start
905 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( 3 ), true );
906
907 for( int i = 4; i <= 8; i++ )
908 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( i ), false );
909
910 for( int i = 3; i <= 7; i++ )
911 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( i ), false );
912
913 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( 9 ), true );
914 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 9 ), expectedSliceArc0.GetP1() ); // equal to arc end
915 }
916
920 BOOST_TEST_CONTEXT( "Case 2: Start at middle of an arc, finish at arc startpoint" )
921 {
922 SHAPE_LINE_CHAIN sliceResult = chain.Slice( 5, 12 );
923 BOOST_CHECK( GEOM_TEST::IsOutlineValid( sliceResult ) );
924
925 BOOST_CHECK_EQUAL( sliceResult.ArcCount(), 1 );
926 SHAPE_ARC expectedSliceArc0;
927 expectedSliceArc0.ConstructFromStartEndCenter( chain.GetPoint( 5 ), firstArc.GetP1(),
928 firstArc.GetCenter(),
929 firstArc.IsClockwise() );
930
931 BOOST_CHECK_EQUAL( sliceResult.Arc( 0 ).GetP1(),
932 expectedSliceArc0.GetP1() ); // equal arc end points
933 BOOST_CHECK( sliceResult.Arc( 0 ).Collide( expectedSliceArc0.GetArcMid(), tol ) );
934 BOOST_CHECK( sliceResult.Arc( 0 ).Collide( expectedSliceArc0.GetP0(), tol ) );
935
936 BOOST_CHECK_EQUAL( sliceResult.PointCount(), 8 );
937 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 0 ),
938 expectedSliceArc0.GetP0() ); // equal to arc start
939 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( 0 ), true );
940
941 for( int i = 1; i <= 4; i++ )
942 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( i ), false );
943
944 for( int i = 0; i <= 3; i++ )
945 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( i ), false );
946
947 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( 4 ), true );
948 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 4 ),
949 expectedSliceArc0.GetP1() ); // equal to arc end
950
951 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 5 ), targetSegment.A );
952 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 6 ), targetSegment.B );
953 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 7 ), secondArc.GetP0() );
954 }
955
959 BOOST_TEST_CONTEXT( "Case 3: Full arc, nothing else" )
960 {
961 SHAPE_LINE_CHAIN sliceResult = chain.Slice( 3, 9 );
962 BOOST_CHECK( GEOM_TEST::IsOutlineValid( sliceResult ) );
963
964 BOOST_CHECK_EQUAL( sliceResult.ArcCount(), 1 );
965 SHAPE_ARC sliceArc0 = sliceResult.Arc( 0 );
966
967 // Equal arc to original inserted arc
968 BOOST_CHECK_EQUAL( firstArc.GetP1(), sliceArc0.GetP1() );
969 BOOST_CHECK_EQUAL( firstArc.GetArcMid(), sliceArc0.GetArcMid() );
970 BOOST_CHECK_EQUAL( firstArc.GetP1(), sliceArc0.GetP1() );
971
972 BOOST_CHECK_EQUAL( sliceResult.PointCount(), 7 );
973 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 0 ), sliceArc0.GetP0() ); // equal to arc start
974 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( 0 ), true );
975
976 for( int i = 1; i <= 6; i++ )
977 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( i ), false );
978
979 for( int i = 0; i <= 5; i++ )
980 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( i ), false );
981
982 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( 6 ), true );
983 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 6 ), sliceArc0.GetP1() ); // equal to arc end
984 }
985
989 BOOST_TEST_CONTEXT( "Case 4: Full arc, and straight segments to next arc start" )
990 {
991 SHAPE_LINE_CHAIN sliceResult = chain.Slice( 3, 12 );
992 BOOST_CHECK( GEOM_TEST::IsOutlineValid( sliceResult ) );
993
994 BOOST_CHECK_EQUAL( sliceResult.ArcCount(), 1 );
995 SHAPE_ARC sliceArc0 = sliceResult.Arc( 0 );
996
997 // Equal arc to original inserted arc
998 BOOST_CHECK_EQUAL( firstArc.GetP1(), sliceArc0.GetP1() );
999 BOOST_CHECK_EQUAL( firstArc.GetArcMid(), sliceArc0.GetArcMid() );
1000 BOOST_CHECK_EQUAL( firstArc.GetP1(), sliceArc0.GetP1() );
1001
1002 BOOST_CHECK_EQUAL( sliceResult.PointCount(), 10 );
1003 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 0 ), sliceArc0.GetP0() ); // equal to arc start
1004 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( 0 ), true );
1005
1006 for( int i = 1; i <= 6; i++ )
1007 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( i ), false );
1008
1009 for( int i = 0; i <= 5; i++ )
1010 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( i ), false );
1011
1012 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( 6 ), true );
1013 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 6 ), sliceArc0.GetP1() ); // equal to arc end
1014
1015 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 7 ), targetSegment.A );
1016 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 8 ), targetSegment.B );
1017 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 9 ), secondArc.GetP0() );
1018 }
1019
1020 BOOST_TEST_CONTEXT( "Case 5: Chain ends in arc and point" )
1021 {
1022 SHAPE_LINE_CHAIN chainCopy = chain;
1023 chainCopy.Append( VECTOR2I( 400000, 400000 ) );
1024
1025 SHAPE_LINE_CHAIN sliceResult = chainCopy.Slice( 11, -1 );
1026 BOOST_CHECK( GEOM_TEST::IsOutlineValid( sliceResult ) );
1027 BOOST_CHECK_EQUAL( sliceResult.GetPoint( -1 ), VECTOR2I( 400000, 400000 ) );
1028 }
1029
1030 BOOST_TEST_CONTEXT( "Case 6: Start to end, chain with one point" )
1031 {
1032 SHAPE_LINE_CHAIN chainCopy = SLC_CASES().OnePoint;
1033
1034 SHAPE_LINE_CHAIN sliceResult = chainCopy.Slice( 0, -1 );
1035 BOOST_CHECK_EQUAL( sliceResult.PointCount(), 1 );
1036 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 0 ), VECTOR2I( 233450000, 228360000 ) );
1037 BOOST_CHECK_EQUAL( sliceResult.GetPoint( -1 ), VECTOR2I( 233450000, 228360000 ) ); // Same as index 0
1038 }
1039
1040 BOOST_TEST_CONTEXT( "Case 7: Start to end, chain with two points" )
1041 {
1042 SHAPE_LINE_CHAIN chainCopy = SLC_CASES().TwoPoints;
1043
1044 SHAPE_LINE_CHAIN sliceResult = chainCopy.Slice( 0, -1 );
1045 BOOST_CHECK_EQUAL( sliceResult.PointCount(), 2 );
1046 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 0 ), VECTOR2I( 233450000, 228360000 ) );
1047 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 1 ), VECTOR2I( 263450000, 258360000 ) );
1048 BOOST_CHECK_EQUAL( sliceResult.GetPoint( -1 ), VECTOR2I( 263450000, 258360000 ) ); // Same as index 1
1049 }
1050
1051 BOOST_TEST_CONTEXT( "Case 8: Full 2nd arc, nothing else" )
1052 {
1053 SHAPE_LINE_CHAIN sliceResult = chain.Slice( 12, 19 );
1054 BOOST_CHECK( GEOM_TEST::IsOutlineValid( sliceResult ) );
1055
1056 BOOST_CHECK_EQUAL( sliceResult.ArcCount(), 1 );
1057 SHAPE_ARC sliceArc0 = sliceResult.Arc( 0 );
1058
1059 // Equal arc to original inserted arc
1060 BOOST_CHECK_EQUAL( secondArc.GetP1(), sliceArc0.GetP1() );
1061 BOOST_CHECK_EQUAL( secondArc.GetArcMid(), sliceArc0.GetArcMid() );
1062 BOOST_CHECK_EQUAL( secondArc.GetP1(), sliceArc0.GetP1() );
1063
1064 BOOST_CHECK_EQUAL( sliceResult.PointCount(), 8 );
1065 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 0 ), sliceArc0.GetP0() ); // equal to arc start
1066 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( 0 ), true );
1067
1068 for( int i = 1; i <= 7; i++ )
1069 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( i ), false );
1070
1071 for( int i = 0; i <= 6; i++ )
1072 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( i ), false );
1073
1074 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( 7 ), true );
1075 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 7 ), sliceArc0.GetP1() ); // equal to arc end
1076 }
1077
1078 BOOST_TEST_CONTEXT( "Case 9: Start at middle of a 2nd arc, finish at end" )
1079 {
1080 SHAPE_LINE_CHAIN sliceResult = chain.Slice( 16, 19 );
1081 BOOST_CHECK( GEOM_TEST::IsOutlineValid( sliceResult ) );
1082
1083 BOOST_CHECK_EQUAL( sliceResult.ArcCount(), 1 );
1084
1085 SHAPE_ARC expectedSliceArc0;
1086 expectedSliceArc0.ConstructFromStartEndCenter( chain.GetPoint( 16 ), secondArc.GetP1(),
1087 secondArc.GetCenter(),
1088 secondArc.IsClockwise() );
1089
1090 BOOST_CHECK_EQUAL( sliceResult.Arc( 0 ).GetP1(),
1091 expectedSliceArc0.GetP1() ); // equal arc end points
1092 BOOST_CHECK( sliceResult.Arc( 0 ).Collide( expectedSliceArc0.GetArcMid(), tol ) );
1093 BOOST_CHECK( sliceResult.Arc( 0 ).Collide( expectedSliceArc0.GetP0(), tol ) );
1094
1095 BOOST_CHECK_EQUAL( sliceResult.PointCount(), 4 );
1096 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 0 ),
1097 expectedSliceArc0.GetP0() ); // equal to arc start
1098 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( 0 ), true );
1099
1100 for( int i = 1; i <= 3; i++ )
1101 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( i ), false );
1102
1103 for( int i = 0; i <= 2; i++ )
1104 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( i ), false );
1105
1106 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( 3 ), true );
1107 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 3 ),
1108 expectedSliceArc0.GetP1() ); // equal to arc end
1109 }
1110
1111 BOOST_TEST_CONTEXT( "Case 10: New chain, start at arc middle, finish at end" )
1112 {
1113 SHAPE_LINE_CHAIN chain10;
1114 chain10.Append( firstArc );
1115
1116 SHAPE_LINE_CHAIN sliceResult = chain10.Slice( 3, 6 );
1117 BOOST_CHECK( GEOM_TEST::IsOutlineValid( sliceResult ) );
1118
1119 BOOST_CHECK_EQUAL( sliceResult.ArcCount(), 1 );
1120
1121 SHAPE_ARC expectedSliceArc0;
1122 expectedSliceArc0.ConstructFromStartEndCenter( chain10.GetPoint( 3 ), firstArc.GetP1(),
1123 firstArc.GetCenter(),
1124 firstArc.IsClockwise() );
1125
1126 BOOST_CHECK_EQUAL( sliceResult.Arc( 0 ).GetP1(),
1127 expectedSliceArc0.GetP1() ); // equal arc end points
1128 BOOST_CHECK( sliceResult.Arc( 0 ).Collide( expectedSliceArc0.GetArcMid(), tol ) );
1129 BOOST_CHECK( sliceResult.Arc( 0 ).Collide( expectedSliceArc0.GetP0(), tol ) );
1130
1131 BOOST_CHECK_EQUAL( sliceResult.PointCount(), 4 );
1132 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 0 ),
1133 expectedSliceArc0.GetP0() ); // equal to arc start
1134 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( 0 ), true );
1135
1136 for( int i = 1; i <= 3; i++ )
1137 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( i ), false );
1138
1139 for( int i = 0; i <= 2; i++ )
1140 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( i ), false );
1141
1142 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( 3 ), true );
1143 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 3 ),
1144 expectedSliceArc0.GetP1() ); // equal to arc end
1145 }
1146}
1147
1148
1149// Test SHAPE_LINE_CHAIN::NearestPoint( VECTOR2I )
1150BOOST_AUTO_TEST_CASE( NearestPointPt )
1151{
1152 SEG seg1( VECTOR2I( 0, 100000 ), VECTOR2I( 50000, 0 ) );
1153 SEG seg2( VECTOR2I( 200000, 0 ), VECTOR2I( 300000, 0 ) );
1154 SHAPE_ARC arc( VECTOR2I( 200000, 0 ), VECTOR2I( 300000, 0 ), ANGLE_180 );
1155
1156 // Start a chain with 2 points (seg1)
1157 SHAPE_LINE_CHAIN chain( { seg1.A, seg1.B } );
1158 BOOST_CHECK_EQUAL( chain.PointCount(), 2 );
1159 // Add first arc
1160 chain.Append( arc );
1161 BOOST_CHECK_EQUAL( chain.PointCount(), 9 );
1162 // Add two points (seg2)
1163 chain.Append( seg2.A );
1164 chain.Append( seg2.B );
1165 BOOST_CHECK_EQUAL( chain.PointCount(), 11 );
1167
1168 VECTOR2I ptOnArcCloseToStart( 297553, 31697 ); //should be index 3 in chain
1169 VECTOR2I ptOnArcCloseToEnd( 139709, 82983 ); //should be index 6 in chain
1170
1171 BOOST_CHECK_EQUAL( chain.NearestPoint( ptOnArcCloseToStart, true ), ptOnArcCloseToStart );
1172 BOOST_CHECK_EQUAL( chain.NearestPoint( ptOnArcCloseToStart, false ), arc.GetP0() );
1173
1174 BOOST_CHECK_EQUAL( chain.NearestPoint( ptOnArcCloseToEnd, true ), ptOnArcCloseToEnd );
1175 BOOST_CHECK_EQUAL( chain.NearestPoint( ptOnArcCloseToEnd, false ), arc.GetP1() );
1176}
1177
1178
1179// Test SHAPE_LINE_CHAIN::Replace( SHAPE_LINE_CHAIN )
1181{
1182 BOOST_TEST_INFO( "8949 crash" );
1183
1184 std::vector<VECTOR2I> linePts = {
1185 { 206000000, 140110000 }, { 192325020, 140110000 }, { 192325020, 113348216 },
1186 { 192251784, 113274980 }, { 175548216, 113274980 }, { 175474980, 113348216 },
1187 { 175474980, 136694980 }, { 160774511, 121994511 }, { 160774511, 121693501 },
1188 { 160086499, 121005489 }, { 159785489, 121005489 }, { 159594511, 120814511 },
1189 { 160086499, 120814511 }, { 160774511, 120126499 }, { 160774511, 119153501 },
1190 { 160086499, 118465489 }, { 159113501, 118465489 }, { 158425489, 119153501 },
1191 { 158425489, 119645489 }, { 157325020, 118545020 }, { 157325020, 101925020 },
1192 { 208674980, 101925020 }, { 208674980, 145474980 }, { 192325020, 145474980 },
1193 { 192325020, 140110000 }
1194 };
1195
1196 SHAPE_LINE_CHAIN baseChain( linePts, false );
1197 baseChain.SetWidth( 250000 );
1198 BOOST_CHECK_EQUAL( baseChain.PointCount(), linePts.size() );
1199
1200 SHAPE_LINE_CHAIN replaceChain( { VECTOR2I( 192325020, 140110000 ) }, false );
1201 BOOST_CHECK_EQUAL( replaceChain.PointCount(), 1 );
1202
1203 baseChain.Replace( 1, 23, replaceChain );
1204
1205 BOOST_CHECK_EQUAL( baseChain.PointCount(), linePts.size() - ( 23 - 1 ) );
1206
1207 // Replacing the last point in a chain is special-cased
1208 baseChain.Replace( baseChain.PointCount() - 1, baseChain.PointCount() - 1, VECTOR2I( -1, -1 ) );
1209
1210 BOOST_CHECK_EQUAL( baseChain.CLastPoint(), VECTOR2I( -1, -1 ) );
1211}
1212
1213
1214BOOST_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:115
bool IsClockwise() const
Definition: shape_arc.h:263
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:114
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:222
const VECTOR2I & GetP0() const
Definition: shape_arc.h:113
const VECTOR2I & GetCenter() const
Definition: shape_arc.cpp:505
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
#define BOOST_TEST_CONTEXT(A)
#define BOOST_TEST_INFO(A)
If HAVE_EXPECTED_FAILURES is defined, this means that boost::unit_test::expected_failures is availabl...
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:676