KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_shape_line_chain.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.TXT for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24#include <geometry/shape_arc.h>
26#include <trigo.h>
27
29#include <qa_utils/numeric.h>
31
32#include "geom_test_utils.h"
33
39{
53
60
62 {
63 ArcCircle = SHAPE_ARC( VECTOR2I( 183450000, 128360000 ),
64 VECTOR2I( 183850000, 128360000 ),
65 VECTOR2I( 183450000, 128360000 ), 0 );
66
67 Arc0a = SHAPE_ARC( VECTOR2I( 183450000, 128360000 ),
68 VECTOR2I( 183650000, 128560000 ),
69 VECTOR2I( 183850000, 128360000 ), 0 );
70
71 Arc0b = SHAPE_ARC( VECTOR2I( 183850000, 128360000 ),
72 VECTOR2I( 183650000, 128160000 ),
73 VECTOR2I( 183450000, 128360000 ), 0 );
74
75 Arc1 = SHAPE_ARC( VECTOR2I( 183850000, 128360000 ),
76 VECTOR2I( 183638550, 128640305 ),
77 VECTOR2I( 183500000, 129204974 ), 0 );
78
79 Arc2 = SHAPE_ARC( VECTOR2I( 283450000, 228360000 ),
80 VECTOR2I( 283650000, 228560000 ),
81 VECTOR2I( 283850000, 228360000 ), 0 );
82
83 Arc3 = SHAPE_ARC( VECTOR2I( 0, 0 ),
84 VECTOR2I( 24142136, 10000000 ),
85 VECTOR2I( 0, 20000000 ), 0 );
86
88 Circle1Arc.SetClosed( true );
89
92 Circle2Arcs.SetClosed( true );
93
96
99
102
104 DuplicateArcs.Append( Arc1 ); //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 Clipper2Lib::Path64 pathClipper2 = {
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
150 std::vector<CLIPPER_Z_VALUE> z_values = {
151 { { -1, -1 }, 0 }, { { -1, -1 }, 0 }, { { -1, -1 }, 0 }, { { -1, -1 }, 0 },
152 { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 },
153 { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 },
154 { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 },
155 { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 },
156 { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 },
157 { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 },
158 { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 },
159 { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 },
160 { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 },
161 { { 0, -1 }, 0 }
162 };
163
164 std::vector<SHAPE_ARC> arcs = {
165 SHAPE_ARC( { 127171000, 123786000 }, { 126231718, 120077003 }, { 124598846, 123537154 }, 0 )
166 };
167
168 SHAPE_LINE_CHAIN clipper2chain( pathClipper2, z_values, arcs );
169
170 BOOST_CHECK( GEOM_TEST::IsOutlineValid( clipper2chain ) );
171
172 BOOST_CHECK_EQUAL( clipper2chain.PointCount(), 37 );
173
174 BOOST_CHECK_EQUAL( clipper2chain.ArcCount(), 1 );
175
176 BOOST_CHECK_EQUAL( clipper2chain.ShapeCount(), 2 );
177
178 BOOST_CHECK_EQUAL( clipper2chain.IsClosed(), true );
179}
180
181
182BOOST_AUTO_TEST_CASE( ArcToPolyline )
183{
184 SHAPE_LINE_CHAIN base_chain( { VECTOR2I( 0, 0 ), VECTOR2I( 0, 1000 ), VECTOR2I( 1000, 0 ) } );
185
186 SHAPE_LINE_CHAIN chain_insert( {
187 VECTOR2I( 0, 1500 ),
188 VECTOR2I( 1500, 1500 ),
189 VECTOR2I( 1500, 0 ),
190 } );
191
192 SHAPE_LINE_CHAIN arc_insert1( SHAPE_ARC( VECTOR2I( 0, -100 ), VECTOR2I( 0, -200 ), ANGLE_180 ) );
193
194 SHAPE_LINE_CHAIN arc_insert2( SHAPE_ARC( VECTOR2I( 0, 500 ), VECTOR2I( 0, 400 ), ANGLE_180 ) );
195
196 BOOST_CHECK_EQUAL( base_chain.CShapes().size(), base_chain.CPoints().size() );
197 BOOST_CHECK_EQUAL( arc_insert1.CShapes().size(), arc_insert1.CPoints().size() );
198 BOOST_CHECK_EQUAL( arc_insert2.CShapes().size(), arc_insert2.CPoints().size() );
199
200 BOOST_CHECK( GEOM_TEST::IsOutlineValid( base_chain ) );
201 BOOST_CHECK( GEOM_TEST::IsOutlineValid( arc_insert1 ) );
202 BOOST_CHECK( GEOM_TEST::IsOutlineValid( arc_insert2 ) );
203
204 base_chain.Insert( 0, SHAPE_ARC( VECTOR2I( 0, -100 ), VECTOR2I( 0, -200 ), ANGLE_180 ) );
205 BOOST_CHECK( GEOM_TEST::IsOutlineValid( base_chain ) );
206 BOOST_CHECK_EQUAL( base_chain.CShapes().size(), base_chain.CPoints().size() );
207
208 base_chain.Replace( 0, 2, chain_insert );
209 BOOST_CHECK( GEOM_TEST::IsOutlineValid( base_chain ) );
210 BOOST_CHECK_EQUAL( base_chain.CShapes().size(), base_chain.CPoints().size() );
211}
212
213
214// Similar test to above but with larger coordinates, so we have more than one point per arc
215BOOST_AUTO_TEST_CASE( ArcToPolylineLargeCoords )
216{
217 SHAPE_LINE_CHAIN base_chain( { VECTOR2I( 0, 0 ), VECTOR2I( 0, 100000 ), VECTOR2I( 100000, 0 ) } );
218
219 SHAPE_LINE_CHAIN chain_insert( {
220 VECTOR2I( 0, 1500000 ),
221 VECTOR2I( 1500000, 1500000 ),
222 VECTOR2I( 1500000, 0 ),
223 } );
224
225 base_chain.Append( SHAPE_ARC( VECTOR2I( 200000, 0 ), VECTOR2I( 300000, 100000 ), ANGLE_180 ) );
226
227 BOOST_CHECK( GEOM_TEST::IsOutlineValid( base_chain ) );
228 BOOST_CHECK_EQUAL( base_chain.PointCount(), 11 );
229
230 base_chain.Insert( 9, VECTOR2I( 250000, 0 ) );
231 BOOST_CHECK( GEOM_TEST::IsOutlineValid( base_chain ) );
232 BOOST_CHECK_EQUAL( base_chain.PointCount(), 12 );
233 BOOST_CHECK_EQUAL( base_chain.ArcCount(), 2 ); // Should have two arcs after the split
234
235 base_chain.Replace( 5, 6, chain_insert );
236 BOOST_CHECK( GEOM_TEST::IsOutlineValid( base_chain ) );
237 BOOST_CHECK_EQUAL( base_chain.PointCount(), 13 ); // Adding 3 points, removing 2
238 BOOST_CHECK_EQUAL( base_chain.ArcCount(), 3 ); // Should have three arcs after the split
239
240 base_chain.Replace( 4, 6, VECTOR2I( 550000, 0 ) );
241 BOOST_CHECK( GEOM_TEST::IsOutlineValid( base_chain ) );
242 BOOST_CHECK_EQUAL( base_chain.PointCount(), 11 ); // Adding 1 point, removing 3
243 BOOST_CHECK_EQUAL( base_chain.ArcCount(), 3 ); // Should still have three arcs
244
245 // Test ClearArcs
246 base_chain.SetClosed( true );
247 double areaPriorToArcRemoval = base_chain.Area();
248 base_chain.ClearArcs();
249
250 BOOST_CHECK( GEOM_TEST::IsOutlineValid( base_chain ) );
251 BOOST_CHECK_EQUAL( base_chain.CPoints().size(), base_chain.CShapes().size() );
252 BOOST_CHECK_EQUAL( base_chain.PointCount(), 11 ); // We should have the same number of points
253 BOOST_CHECK_EQUAL( base_chain.ArcCount(), 0 ); // All arcs should have been removed
254 BOOST_CHECK_EQUAL( base_chain.Area(), areaPriorToArcRemoval ); // Area should not have changed
255}
256
257// Test that duplicate point gets removed when line is set to be closed and added where required
258BOOST_AUTO_TEST_CASE( SetClosedDuplicatePoint )
259{
260 // Test from issue #9843
261 SHAPE_LINE_CHAIN chain;
262
263 chain.Append(
264 SHAPE_ARC( { -859598, 2559876 }, { -1632771, 1022403 }, { -3170244, 249230 }, 0 ) );
265
266 chain.Append(
267 SHAPE_ARC( { -3170244, -1657832 }, { -292804, -317564 }, { 1047464, 2559876 }, 0 ) );
268
269 chain.Append( VECTOR2I( -859598, 2559876 ) ); // add point that is equal to first arc start
270
271 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
272 BOOST_CHECK_EQUAL( chain.PointCount(), 31 );
273
274 // CLOSED CHAIN
275 chain.SetClosed( true );
276 BOOST_CHECK_EQUAL( chain.CPoints().size(), chain.CShapes().size() );
277 BOOST_CHECK_EQUAL( chain.PointCount(), 30 ); // (-1) should have removed coincident points
278 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
279
280 // Special case: arc wrapping around to start (e.g. circle)
281 BOOST_CHECK( GEOM_TEST::IsOutlineValid( Circle2Arcs ) );
282 BOOST_CHECK_EQUAL( Circle2Arcs.IsClosed(), true );
283 BOOST_CHECK_EQUAL( Circle2Arcs.PointCount(), 16 );
284 BOOST_CHECK_EQUAL( Circle2Arcs.IsArcSegment( 15 ), true );
285 BOOST_CHECK_EQUAL( Circle2Arcs.ShapeCount(), 2 );
286 Circle2Arcs.SetClosed( false );
287 BOOST_CHECK( GEOM_TEST::IsOutlineValid( Circle2Arcs ) );
288 BOOST_CHECK_EQUAL( Circle2Arcs.IsClosed(), false );
289 BOOST_CHECK_EQUAL( Circle2Arcs.PointCount(), 17 );
290 BOOST_CHECK_EQUAL( Circle2Arcs.IsArcSegment( 15 ), true );
291 BOOST_CHECK_EQUAL( Circle2Arcs.IsArcSegment( 16 ), false ); // last point doesn't join up
292}
293
295{
296 std::string m_ctx_name;
303};
304
305static const std::vector<CLOSE_TOGGLE_SHAPE_CASE> close_toggle_shape_cases =
306 {
307 { "Circle1Arc", SLC_CASES().Circle1Arc, true, 1, 15, 1, 16 },
308 { "Circle2Arcs", SLC_CASES().Circle2Arcs, true, 2, 16, 2, 17 },
309 { "ArcsCoincident", SLC_CASES().ArcsCoincident, false, 2, 14, 3, 14 },
310 { "ArcsCoincidentClosed", SLC_CASES().ArcsCoincidentClosed, true, 3, 14, 2, 14 },
311 { "ArcsIndependent", SLC_CASES().ArcsIndependent, false, 3, 18, 4, 18 },
312 // SegAndArcCoincident will remove the segment after SetClosed(true) and SetClosed(false)
313 // disable test for now
314 //{ "SegAndArcCoincident", SLC_CASES().SegAndArcCoincident, false, 2, 92, 2, 91 },
315 { "DuplicateArcs", SLC_CASES().DuplicateArcs, false, 4, 20, 5, 20 },
316 { "ArcAndPoint", SLC_CASES().ArcAndPoint, false, 2, 10, 3, 10 },
317 { "ArcsAndSegMixed", SLC_CASES().ArcsAndSegMixed, false, 4, 19, 5, 19 },
318 { "OnePoint", SLC_CASES().OnePoint, false, 0, 1, 0, 1 }, // no shapes
319 { "TwoPoints", SLC_CASES().TwoPoints, false, 1, 2, 2, 2 }, // there and back
320 { "ThreePoints", SLC_CASES().ThreePoints, false, 2, 3, 3, 3 },
321 };
322
323BOOST_AUTO_TEST_CASE( ToggleClosed )
324{
326 {
327 BOOST_TEST_CONTEXT( c.m_ctx_name )
328 {
329 SHAPE_LINE_CHAIN slc_case = c.m_chain; // make a copy to edit
330 BOOST_CHECK( GEOM_TEST::IsOutlineValid( slc_case ) );
331 BOOST_CHECK_EQUAL( slc_case.IsClosed(), c.m_closed );
332 BOOST_CHECK_EQUAL( slc_case.ShapeCount(), c.m_shape_count );
333 BOOST_CHECK_EQUAL( slc_case.PointCount(), c.m_point_count );
334 slc_case.SetClosed( !c.m_closed );
335 BOOST_CHECK( GEOM_TEST::IsOutlineValid( slc_case ) );
336 BOOST_CHECK_EQUAL( slc_case.IsClosed(), !c.m_closed );
337 BOOST_CHECK_EQUAL( slc_case.ShapeCount(), c.m_expected_shape_count );
338 BOOST_CHECK_EQUAL( slc_case.PointCount(), c.m_expected_point_count );
339 slc_case.SetClosed( c.m_closed ); // toggle back to normal
340 BOOST_CHECK( GEOM_TEST::IsOutlineValid( slc_case ) );
341 BOOST_CHECK_EQUAL( slc_case.IsClosed(), c.m_closed );
342 BOOST_CHECK_EQUAL( slc_case.ShapeCount(), c.m_shape_count );
343 BOOST_CHECK_EQUAL( slc_case.PointCount(), c.m_point_count );
344 }
345 }
346}
347
348
349BOOST_AUTO_TEST_CASE( PointInPolygon )
350{
351 SHAPE_LINE_CHAIN outline1( { { 1316455, 913576 }, { 1316455, 901129 }, { 1321102, 901129 },
352 { 1322152, 901191 }, { 1323055, 901365 }, { 1323830, 901639 },
353 { 1324543, 902036 }, { 1325121, 902521 }, { 1325581, 903100 },
354 { 1325914, 903759 }, { 1326120, 904516 }, { 1326193, 905390 },
355 { 1326121, 906253 }, { 1325915, 907005 }, { 1325581, 907667 },
356 { 1325121, 908248 }, { 1324543, 908735 }, { 1323830, 909132 },
357 { 1323055, 909406 }, { 1322153, 909579 }, { 1321102, 909641 },
358 { 1317174, 909641 }, { 1317757, 909027 }, { 1317757, 913576 } } );
359 SHAPE_LINE_CHAIN outline2( { { 1297076, 916244 }, { 1284629, 916244 }, { 1284629, 911597 },
360 { 1284691, 910547 }, { 1284865, 909644 }, { 1285139, 908869 },
361 { 1285536, 908156 }, { 1286021, 907578 }, { 1286600, 907118 },
362 { 1287259, 906785 }, { 1288016, 906579 }, { 1288890, 906506 },
363 { 1289753, 906578 }, { 1290505, 906784 }, { 1291167, 907118 },
364 { 1291748, 907578 }, { 1292235, 908156 }, { 1292632, 908869 },
365 { 1292906, 909644 }, { 1293079, 910546 }, { 1293141, 911597 },
366 { 1293141, 915525 }, { 1292527, 914942 }, { 1297076, 914942 } } );
367
368 // Test a point inside the polygon
369 VECTOR2I point1( 1317757, 909133 );
370 VECTOR2I point2( 1292633, 914942 );
371
372 outline1.SetClosed( true );
373 outline2.SetClosed( true );
374
375 BOOST_CHECK( outline1.PointInside( point1, 0, false ) );
376 BOOST_CHECK( outline2.PointInside( point2, 0, false ) );
377}
378
379// Test that duplicate point gets removed when we call simplify
380BOOST_AUTO_TEST_CASE( SimplifyDuplicatePoint )
381{
382 SHAPE_LINE_CHAIN chain;
383
384 chain.Append( { 100, 100 } );
385 chain.Append( { 100, 100 }, true ); //duplicate point to simplify
386 chain.Append( { 200, 100 } );
387
388 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
389 BOOST_CHECK_EQUAL( chain.PointCount(), 3 );
390
391 chain.Simplify();
392
393 BOOST_CHECK_EQUAL( chain.CPoints().size(), chain.CShapes().size() );
394 BOOST_CHECK_EQUAL( chain.PointCount(), 2 ); // (-1) should have removed coincident points
395 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
396}
397
398
399// Test that duplicate point gets removed when we call simplify
400BOOST_AUTO_TEST_CASE( SimplifyKeepEndPoint )
401{
402 SHAPE_LINE_CHAIN chain;
403
404 chain.Append( { 114772424, 90949410 } );
405 chain.Append( { 114767360, 90947240 } );
406 chain.Append( { 114772429, 90947228 } );
407 chain.SetClosed( true );
408
409 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
410 BOOST_CHECK_EQUAL( chain.PointCount(), 3 );
411
412 chain.Simplify();
413
414 BOOST_CHECK_EQUAL( chain.CPoints().size(), chain.CShapes().size() );
415 BOOST_CHECK_EQUAL( chain.PointCount(), 3 );
416 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
417}
418
419
420BOOST_AUTO_TEST_CASE( SimplifyPNSChain )
421{
422 SHAPE_LINE_CHAIN chain;
423 chain.Append( VECTOR2I( 157527820, 223074385 ) );
424 chain.Append( VECTOR2I( 186541122, 159990156 ) );
425 chain.Append( VECTOR2I( 186528624, 159977658 ) );
426 chain.Append( VECTOR2I( 186528624, 159770550 ) );
427 chain.Append( VECTOR2I( 186528625, 159366691 ) );
428 chain.Append( VECTOR2I( 186541122, 159354195 ) );
429 chain.Append( VECTOR2I( 186541122, 155566877 ) );
430 chain.Append( VECTOR2I( 187291125, 154816872 ) );
431 chain.Append( VECTOR2I( 187291125, 147807837 ) );
432 chain.Append( VECTOR2I( 189301788, 145797175 ) );
433 chain.Append( VECTOR2I( 194451695, 145797175 ) );
434 chain.Append( VECTOR2I( 195021410, 146366890 ) );
435
436 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
437 BOOST_CHECK_EQUAL( chain.PointCount(), 12 );
438
439 // The chain should be open, so the points should not be simplified
440 // between the begining and the end.
441 chain.Simplify( 10 );
442
443 BOOST_CHECK_EQUAL( chain.PointCount(), 11 );
444}
445
446
447BOOST_AUTO_TEST_CASE( SimplifyComplexChain )
448{
449 SHAPE_LINE_CHAIN chain;
450
451 // Append points
452 chain.Append( { 130000, 147320 } );
453 chain.Append( { 125730, 147320 } );
454 chain.Append( { 125730, 150630 } );
455 chain.Append( { 128800, 153700 } );
456 chain.Append( { 150300, 153700 } );
457 chain.Append( { 151500, 152500 } );
458 chain.Append( { 151500, 148900 } );
459 chain.Append( { 149920, 147320 } );
460 chain.Append( { 140000, 147320 } );
461
462 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
463 BOOST_CHECK_EQUAL( chain.PointCount(), 9 );
464
465 // The chain should be open, so the points should not be simplified
466 // between the begining and the end.
467 chain.Simplify();
468
469 BOOST_CHECK_EQUAL( chain.PointCount(), 9 );
470
471 chain.SetClosed( true );
472 chain.Simplify();
473
474 BOOST_CHECK_EQUAL( chain.PointCount(), 8 );
475}
476
478{
479 std::string m_ctx_name;
486};
487
488static const std::vector<REMOVE_SHAPE_CASE> remove_shape_cases =
489 {
490 { "Circle1Arc - 1st arc - index on start", SLC_CASES().Circle1Arc, 1, 1, 0, 0, 0 },
491 { "Circle1Arc - 1st arc - index on mid", SLC_CASES().Circle1Arc, 1, 1, 8, 0, 0 },
492 { "Circle1Arc - 1st arc - index on end", SLC_CASES().Circle1Arc, 1, 1, 14, 0, 0 },
493 { "Circle1Arc - 1st arc - index on -1", SLC_CASES().Circle1Arc, 1, 1, -1, 0, 0 },
494 { "Circle1Arc - invalid index", SLC_CASES().Circle1Arc, 1, 1, 15, 1, 1 },
495
496 { "Circle2Arcs - 1st arc - index on start", SLC_CASES().Circle2Arcs, 2, 2, 0, 2, 1 },
497 { "Circle2Arcs - 1st arc - index on mid", SLC_CASES().Circle2Arcs, 2, 2, 3, 2, 1 },
498 { "Circle2Arcs - 1st arc - index on end", SLC_CASES().Circle2Arcs, 2, 2, 7, 2, 1 },
499 { "Circle2Arcs - 2nd arc - index on start", SLC_CASES().Circle2Arcs, 2, 2, 8, 2, 1 },
500 { "Circle2Arcs - 2nd arc - index on mid", SLC_CASES().Circle2Arcs, 2, 2, 11, 2, 1 },
501 { "Circle2Arcs - 2nd arc - index on end", SLC_CASES().Circle2Arcs, 2, 2, 15, 2, 1 },
502 { "Circle2Arcs - 2nd arc - index on -1", SLC_CASES().Circle2Arcs, 2, 2, -1, 2, 1 },
503 { "Circle2Arcs - invalid index", SLC_CASES().Circle2Arcs, 2, 2, 16, 2, 2 },
504
505 { "ArcsCoinc. - 1st arc - idx on start", SLC_CASES().ArcsCoincident, 2, 2, 0, 1, 1 },
506 { "ArcsCoinc. - 1st arc - idx on mid", SLC_CASES().ArcsCoincident, 2, 2, 3, 1, 1 },
507 { "ArcsCoinc. - 1st arc - idx on end", SLC_CASES().ArcsCoincident, 2, 2, 7, 1, 1 },
508 { "ArcsCoinc. - 2nd arc - idx on start", SLC_CASES().ArcsCoincident, 2, 2, 8, 1, 1 },
509 { "ArcsCoinc. - 2nd arc - idx on mid", SLC_CASES().ArcsCoincident, 2, 2, 10, 1, 1 },
510 { "ArcsCoinc. - 2nd arc - idx on end", SLC_CASES().ArcsCoincident, 2, 2, 13, 1, 1 },
511 { "ArcsCoinc. - 2nd arc - idx on -1", SLC_CASES().ArcsCoincident, 2, 2, -1, 1, 1 },
512 { "ArcsCoinc. - invalid idx", SLC_CASES().ArcsCoincident, 2, 2, 14, 2, 2 },
513 { "ArcsCoinc. - 1st arc - idx on start", SLC_CASES().ArcsCoincident, 2, 2, 0, 1, 1 },
514
515 { "A.Co.Closed - 1st arc - idx on start", SLC_CASES().ArcsCoincidentClosed, 3, 2, 1, 2, 1 },
516 { "A.Co.Closed - 1st arc - idx on mid", SLC_CASES().ArcsCoincidentClosed, 3, 2, 3, 2, 1 },
517 { "A.Co.Closed - 1st arc - idx on end", SLC_CASES().ArcsCoincidentClosed, 3, 2, 7, 2, 1 },
518 { "A.Co.Closed - 2nd arc - idx on start", SLC_CASES().ArcsCoincidentClosed, 3, 2, 8, 2, 1 },
519 { "A.Co.Closed - 2nd arc - idx on mid", SLC_CASES().ArcsCoincidentClosed, 3, 2, 10, 2, 1 },
520 { "A.Co.Closed - 2nd arc - idx on end", SLC_CASES().ArcsCoincidentClosed, 3, 2, 13, 2, 1 },
521 { "A.Co.Closed - 2nd arc - idx on -1", SLC_CASES().ArcsCoincidentClosed, 3, 2, -1, 2, 1 },
522 { "A.Co.Closed - invalid idx", SLC_CASES().ArcsCoincidentClosed, 3, 2, 14, 3, 2 },
523
524 { "ArcsIndep. - 1st arc - idx on start", SLC_CASES().ArcsIndependent, 3, 2, 0, 1, 1 },
525 { "ArcsIndep. - 1st arc - idx on mid", SLC_CASES().ArcsIndependent, 3, 2, 3, 1, 1 },
526 { "ArcsIndep. - 1st arc - idx on end", SLC_CASES().ArcsIndependent, 3, 2, 8, 1, 1 },
527 { "ArcsIndep. - 2nd arc - idx on start", SLC_CASES().ArcsIndependent, 3, 2, 9, 1, 1 },
528 { "ArcsIndep. - 2nd arc - idx on mid", SLC_CASES().ArcsIndependent, 3, 2, 12, 1, 1 },
529 { "ArcsIndep. - 2nd arc - idx on end", SLC_CASES().ArcsIndependent, 3, 2, 17, 1, 1 },
530 { "ArcsIndep. - 2nd arc - idx on -1", SLC_CASES().ArcsIndependent, 3, 2, -1, 1, 1 },
531 { "ArcsIndep. - invalid idx", SLC_CASES().ArcsIndependent, 3, 2, 18, 3, 2 },
532
533 { "Dup.Arcs - 1st arc - idx on start", SLC_CASES().DuplicateArcs, 4, 3, 0, 3, 2 },
534 { "Dup.Arcs - 1st arc - idx on mid", SLC_CASES().DuplicateArcs, 4, 3, 3, 3, 2 },
535 { "Dup.Arcs - 1st arc - idx on end", SLC_CASES().DuplicateArcs, 4, 3, 7, 3, 2 },
536 { "Dup.Arcs - 2nd arc - idx on start", SLC_CASES().DuplicateArcs, 4, 3, 8, 3, 2 },
537 { "Dup.Arcs - 2nd arc - idx on mid", SLC_CASES().DuplicateArcs, 4, 3, 10, 3, 2 },
538 { "Dup.Arcs - 2nd arc - idx on end", SLC_CASES().DuplicateArcs, 4, 3, 13, 3, 2 },
539 { "Dup.Arcs - 3rd arc - idx on start", SLC_CASES().DuplicateArcs, 4, 3, 14, 2, 2 },
540 { "Dup.Arcs - 3rd arc - idx on mid", SLC_CASES().DuplicateArcs, 4, 3, 17, 2, 2 },
541 { "Dup.Arcs - 3rd arc - idx on end", SLC_CASES().DuplicateArcs, 4, 3, 19, 2, 2 },
542 { "Dup.Arcs - 3rd arc - idx on -1", SLC_CASES().DuplicateArcs, 4, 3, -1, 2, 2 },
543 { "Dup.Arcs - invalid idx", SLC_CASES().DuplicateArcs, 4, 3, 20, 4, 3 },
544
545 { "Arcs Mixed - 1st arc - idx on start", SLC_CASES().ArcsAndSegMixed, 4, 2, 0, 2, 1 },
546 { "Arcs Mixed - 1st arc - idx on mid", SLC_CASES().ArcsAndSegMixed, 4, 2, 3, 2, 1 },
547 { "Arcs Mixed - 1st arc - idx on end", SLC_CASES().ArcsAndSegMixed, 4, 2, 8, 2, 1 },
548 { "Arcs Mixed - Straight segment", SLC_CASES().ArcsAndSegMixed, 4, 2, 9, 3, 2 },
549 { "Arcs Mixed - 2nd arc - idx on start", SLC_CASES().ArcsAndSegMixed, 4, 2, 10, 2, 1 },
550 { "Arcs Mixed - 2nd arc - idx on mid", SLC_CASES().ArcsAndSegMixed, 4, 2, 14, 2, 1 },
551 { "Arcs Mixed - 2nd arc - idx on end", SLC_CASES().ArcsAndSegMixed, 4, 2, 18, 2, 1 },
552 { "Arcs Mixed - 2nd arc - idx on -1", SLC_CASES().ArcsAndSegMixed, 4, 2, -1, 2, 1 },
553 { "Arcs Mixed - invalid idx", SLC_CASES().ArcsAndSegMixed, 4, 2, 19, 4, 2 }
554 };
555
556
558{
559 for( const REMOVE_SHAPE_CASE& c : remove_shape_cases )
560 {
561 BOOST_TEST_CONTEXT( c.m_ctx_name )
562 {
563 SHAPE_LINE_CHAIN slc_case = c.m_chain; // make a copy to edit
564 BOOST_CHECK_EQUAL( slc_case.ShapeCount(), c.m_shape_count );
565 BOOST_CHECK_EQUAL( slc_case.ArcCount(), c.m_arc_count );
566 BOOST_CHECK_EQUAL( GEOM_TEST::IsOutlineValid( slc_case ), true );
567 slc_case.RemoveShape( c.m_remove_index );
568 BOOST_CHECK_EQUAL( slc_case.ShapeCount(), c.m_expected_shape_count );
569 BOOST_CHECK_EQUAL( slc_case.ArcCount(), c.m_expected_arc_count );
570 BOOST_CHECK_EQUAL( GEOM_TEST::IsOutlineValid( slc_case ), true );
571 }
572 }
573}
574
575
576BOOST_AUTO_TEST_CASE( RemoveShapeAfterSimplify )
577{
578 for( const REMOVE_SHAPE_CASE& c : remove_shape_cases )
579 {
580 BOOST_TEST_CONTEXT( c.m_ctx_name )
581 {
582 SHAPE_LINE_CHAIN slc_case = c.m_chain; // make a copy to edit
583 BOOST_CHECK_EQUAL( GEOM_TEST::IsOutlineValid( slc_case ), true );
584 BOOST_CHECK_EQUAL( slc_case.ShapeCount(), c.m_shape_count );
585 BOOST_CHECK_EQUAL( slc_case.ArcCount(), c.m_arc_count );
586 slc_case.Simplify();
587 BOOST_CHECK_EQUAL( GEOM_TEST::IsOutlineValid( slc_case ), true );
588 BOOST_CHECK_EQUAL( slc_case.ShapeCount(), c.m_shape_count );
589 BOOST_CHECK_EQUAL( slc_case.ArcCount(), c.m_arc_count );
590 slc_case.RemoveShape( c.m_remove_index );
591 BOOST_CHECK_EQUAL( GEOM_TEST::IsOutlineValid( slc_case ), true );
592 BOOST_CHECK_EQUAL( slc_case.ShapeCount(), c.m_expected_shape_count );
593 BOOST_CHECK_EQUAL( slc_case.ArcCount(), c.m_expected_arc_count );
594 }
595 }
596}
597
598
600{
601 BOOST_CHECK_EQUAL( Circle1Arc.ShapeCount(), 1 );
602 BOOST_CHECK_EQUAL( Circle2Arcs.ShapeCount(), 2 );
603 BOOST_CHECK_EQUAL( ArcsCoincident.ShapeCount(), 2 );
604 BOOST_CHECK_EQUAL( ArcsCoincidentClosed.ShapeCount(), 3 );
605 BOOST_CHECK_EQUAL( DuplicateArcs.ShapeCount(), 4 );
606 BOOST_CHECK_EQUAL( ArcAndPoint.ShapeCount(), 2 );
607 BOOST_CHECK_EQUAL( ArcsAndSegMixed.ShapeCount(), 4 );
608 BOOST_CHECK_EQUAL( SegAndArcCoincident.ShapeCount(), 2 );
609 BOOST_CHECK_EQUAL( EmptyChain.ShapeCount(), 0 );
610 BOOST_CHECK_EQUAL( OnePoint.ShapeCount(), 0 );
611 BOOST_CHECK_EQUAL( TwoPoints.ShapeCount(), 1 );
612 BOOST_CHECK_EQUAL( ThreePoints.ShapeCount(), 2 );
613}
614
615
617{
618 BOOST_CHECK_EQUAL( Circle1Arc.NextShape( 0 ), -1 ); //only one arc
619
620 BOOST_CHECK_EQUAL( Circle2Arcs.NextShape( 0 ), 8 ); // next shape "Arc0b"
621 BOOST_CHECK_EQUAL( Circle2Arcs.NextShape( 8 ), -1 ); //no more shapes (last point joins with first, part of arc)
622
623 BOOST_CHECK_EQUAL( ArcsCoincident.NextShape( 0 ), 8 ); // next shape "Arc1"
624 BOOST_CHECK_EQUAL( ArcsCoincident.NextShape( 8 ), -1 ); //no more shapes
625
626 BOOST_CHECK_EQUAL( ArcsCoincidentClosed.NextShape( 0 ), 8 ); // next shape "Arc1"
627 BOOST_CHECK_EQUAL( ArcsCoincidentClosed.NextShape( 8 ), 13 ); //next shape is hidden segment joining last/first
628 BOOST_CHECK_EQUAL( ArcsCoincidentClosed.NextShape( 13 ), -1 ); //no more shapes
629
630 BOOST_CHECK_EQUAL( ArcsIndependent.NextShape( 0 ), 8 ); // next shape straight seg
631 BOOST_CHECK_EQUAL( ArcsIndependent.NextShape( 8 ), 9 ); //next shape second arc
632 BOOST_CHECK_EQUAL( ArcsIndependent.NextShape( 9 ), -1 ); //no more shapes
633
634 BOOST_CHECK_EQUAL( DuplicateArcs.NextShape( 0 ), 8 ); // next shape "Arc1"
635 BOOST_CHECK_EQUAL( DuplicateArcs.NextShape( 8 ), 13 ); // next shape hidden segment joining the 2 duplicate arcs
636 BOOST_CHECK_EQUAL( DuplicateArcs.NextShape( 13 ), 14 ); // next shape "Arc1" (duplicate)
637 BOOST_CHECK_EQUAL( DuplicateArcs.NextShape( 14 ), -1 ); //no more shapes
638
639 BOOST_CHECK_EQUAL( ArcAndPoint.NextShape( 0 ), 8 ); // next shape straight segment (end of arc->point)
640 BOOST_CHECK_EQUAL( ArcAndPoint.NextShape( 8 ), -1 ); //no more shapes
641
642 BOOST_CHECK_EQUAL( ArcsAndSegMixed.NextShape( 0 ), 8 ); // next shape straight segment (end of arc->point)
643 BOOST_CHECK_EQUAL( ArcsAndSegMixed.NextShape( 8 ), 9 ); // next shape straight segment (point->begining of arc)
644 BOOST_CHECK_EQUAL( ArcsAndSegMixed.NextShape( 9 ), 10 ); //next shape second arc
645 BOOST_CHECK_EQUAL( ArcsAndSegMixed.NextShape( 10 ), -1 ); //no more shapes
646 BOOST_CHECK_EQUAL( ArcsAndSegMixed.NextShape( 20 ), -1 ); //invalid indices should still work
647 BOOST_CHECK_EQUAL( ArcsAndSegMixed.NextShape( -50 ), -1 ); //invalid indices should still work
648
649 BOOST_CHECK_EQUAL( SegAndArcCoincident.NextShape( 0 ), 1 ); // next shape Arc3
650 BOOST_CHECK_EQUAL( SegAndArcCoincident.NextShape( 1 ), -1 ); //no more shapes
651
652 BOOST_CHECK_EQUAL( EmptyChain.NextShape( 0 ), -1 );
653 BOOST_CHECK_EQUAL( EmptyChain.NextShape( 1 ), -1 ); //invalid indices should still work
654 BOOST_CHECK_EQUAL( EmptyChain.NextShape( 2 ), -1 ); //invalid indices should still work
655 BOOST_CHECK_EQUAL( EmptyChain.NextShape( -2 ), -1 ); //invalid indices should still work
656
657 BOOST_CHECK_EQUAL( OnePoint.NextShape( 0 ), -1 );
658 BOOST_CHECK_EQUAL( OnePoint.NextShape( -1 ), -1 );
659 BOOST_CHECK_EQUAL( OnePoint.NextShape( 1 ), -1 ); //invalid indices should still work
660 BOOST_CHECK_EQUAL( OnePoint.NextShape( 2 ), -1 ); //invalid indices should still work
661 BOOST_CHECK_EQUAL( OnePoint.NextShape( -2 ), -1 ); //invalid indices should still work
662
663 BOOST_CHECK_EQUAL( TwoPoints.NextShape( 0 ), -1 );
664 BOOST_CHECK_EQUAL( TwoPoints.NextShape( 1 ), -1 );
665 BOOST_CHECK_EQUAL( TwoPoints.NextShape( -1 ), -1 );
666
667 BOOST_CHECK_EQUAL( ThreePoints.NextShape( 0 ), 1 );
668 BOOST_CHECK_EQUAL( ThreePoints.NextShape( 1 ), -1 );
669 BOOST_CHECK_EQUAL( ThreePoints.NextShape( 2 ), -1 );
670 BOOST_CHECK_EQUAL( ThreePoints.NextShape( -1 ), -1 );
671}
672
673
674
676{
677 BOOST_TEST_CONTEXT( "Case 1: Arc mid point nearly collinear" )
678 {
679 SHAPE_ARC arc( VECTOR2I( 100000, 0 ), VECTOR2I( 0, 2499 ), VECTOR2I( -100000, 0 ), 0 );
680 SHAPE_LINE_CHAIN chain;
681 chain.Append( arc, 5000 );
682 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
683 BOOST_CHECK_EQUAL( chain.ArcCount(), 0 );
684 BOOST_CHECK_EQUAL( chain.PointCount(), 2 );
685 BOOST_CHECK_EQUAL( chain.GetPoint( 0 ), VECTOR2I( 100000, 0 ) ); //arc start
686 BOOST_CHECK_EQUAL( chain.GetPoint( 1 ), VECTOR2I( -100000, 0 ) ); //arc end
687 BOOST_CHECK_EQUAL( chain.GetPoint( -1 ), VECTOR2I( -100000, 0 ) ); //arc end
688 }
689
690 BOOST_TEST_CONTEXT( "Case 2: Arc = Large Circle" )
691 {
692 SHAPE_ARC arc( VECTOR2I( 100000, 0 ), VECTOR2I( 0, 0 ), VECTOR2I( 100000, 0 ), 0 );
693 SHAPE_LINE_CHAIN chain;
694 chain.Append( arc, 5000 );
695 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
696 BOOST_CHECK_EQUAL( chain.ArcCount(), 1 );
697 BOOST_CHECK_EQUAL( chain.PointCount(), 10 );
698 BOOST_CHECK_EQUAL( chain.GetPoint( 0 ), VECTOR2I( 100000, 0 ) ); //arc start
699 BOOST_CHECK_EQUAL( chain.GetPoint( 9 ), VECTOR2I( 100000, 0 ) ); //arc end
700 BOOST_CHECK_EQUAL( chain.GetPoint( -1 ), VECTOR2I( 100000, 0 ) ); //arc end
701 }
702
703 BOOST_TEST_CONTEXT( "Case 3: Arc = Small Circle (approximate to point)" )
704 {
705 SHAPE_ARC arc( VECTOR2I( 2499, 0 ), VECTOR2I( 0, 0 ), VECTOR2I( 2499, 0 ), 0 );
706 SHAPE_LINE_CHAIN chain;
707 chain.Append( arc, 5000 );
708 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
709 BOOST_CHECK_EQUAL( chain.ArcCount(), 0 );
710 BOOST_CHECK_EQUAL( chain.PointCount(), 1 );
711 BOOST_CHECK_EQUAL( chain.GetPoint( 0 ), VECTOR2I( 2499, 0 ) ); //arc start
712 }
713
714 BOOST_TEST_CONTEXT( "Case 3: Small Arc (approximate to segment)" )
715 {
716 SHAPE_ARC arc( VECTOR2I( 1767, 0 ), VECTOR2I( 2499, 2499 ), VECTOR2I( 0, 1767 ), 0 );
717 SHAPE_LINE_CHAIN chain;
718 chain.Append( arc, 5000 );
719 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
720 BOOST_CHECK_EQUAL( chain.ArcCount(), 0 );
721 BOOST_CHECK_EQUAL( chain.PointCount(), 2 );
722 BOOST_CHECK_EQUAL( chain.GetPoint( 0 ), VECTOR2I( 1767, 0 ) ); //arc start
723 BOOST_CHECK_EQUAL( chain.GetPoint( 1 ), VECTOR2I( 0, 1767 ) ); //arc end
724 }
725
726 BOOST_TEST_CONTEXT( "Case 4: Arc = null arc (all points coincident)" )
727 {
728 SHAPE_ARC arc( VECTOR2I( 2499, 0 ), VECTOR2I( 2499, 0 ), VECTOR2I( 2499, 0 ), 0 );
729 SHAPE_LINE_CHAIN chain;
730 chain.Append( arc, 5000 );
731 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
732 BOOST_CHECK_EQUAL( chain.ArcCount(), 0 );
733 BOOST_CHECK_EQUAL( chain.PointCount(), 1 );
734 BOOST_CHECK_EQUAL( chain.GetPoint( 0 ), VECTOR2I( 2499, 0 ) ); //arc start
735 }
736
737 BOOST_TEST_CONTEXT( "Case 5: Arc = infinite radius (all points very close)" )
738 {
739 SHAPE_ARC arc( VECTOR2I( 2499, 0 ), VECTOR2I( 2500, 0 ), VECTOR2I( 2501, 0 ), 0 );
740 SHAPE_LINE_CHAIN chain;
741 chain.Append( arc, 5000 );
742 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
743 BOOST_CHECK_EQUAL( chain.ArcCount(), 0 );
744 BOOST_CHECK_EQUAL( chain.PointCount(), 2 );
745 BOOST_CHECK_EQUAL( chain.GetPoint( 0 ), VECTOR2I( 2499, 0 ) ); //arc start
746 BOOST_CHECK_EQUAL( chain.GetPoint( 1 ), VECTOR2I( 2501, 0 ) ); //arc end
747 }
748
749 BOOST_TEST_CONTEXT( "Case 6: Arc = large radius (all points very close)" )
750 {
751 SHAPE_ARC arc( VECTOR2I( -100000, 0 ), VECTOR2I( 0, 1 ), VECTOR2I( 100000, 0 ), 0 );
752 SHAPE_LINE_CHAIN chain;
753 chain.Append( arc, 5000 );
754 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
755 BOOST_CHECK_EQUAL( chain.ArcCount(), 0 );
756 BOOST_CHECK_EQUAL( chain.PointCount(), 2 );
757 BOOST_CHECK_EQUAL( chain.GetPoint( 0 ), VECTOR2I( -100000, 0 ) ); //arc start
758 BOOST_CHECK_EQUAL( chain.GetPoint( 1 ), VECTOR2I( 100000, 0 ) ); //arc end
759 }
760}
761
762
763// Test special case where the last arc in the chain has a shared point with the first arc
764BOOST_AUTO_TEST_CASE( ArcWrappingToStartSharedPoints )
765{
766 // represent a circle with two semicircular arcs
767 SHAPE_ARC arc1( VECTOR2I( 100000, 0 ), VECTOR2I( 0, 100000 ), VECTOR2I( -100000, 0 ), 0 );
768 SHAPE_ARC arc2( VECTOR2I( -100000, 0 ), VECTOR2I( 0, -100000 ), VECTOR2I( 100000, 0 ), 0 );
769
770 // Start a chain with the two arcs
771 SHAPE_LINE_CHAIN chain;
772 chain.Append( arc1 );
773 chain.Append( arc2 );
774 BOOST_CHECK_EQUAL( chain.PointCount(), 13 );
775 //BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
776
777 // OPEN CHAIN
778 // Start of the chain is not yet a shared point, so can't be an arc end either
779 BOOST_CHECK_EQUAL( chain.IsSharedPt( 0 ), false );
780 BOOST_CHECK_EQUAL( chain.IsArcEnd( 0 ), false );
781 BOOST_CHECK_EQUAL( chain.IsArcStart( 0 ), true );
782
783 // Index 6 is the shared point between the two arcs in the middle of the chain
784 BOOST_CHECK_EQUAL( chain.IsSharedPt( 6 ), true );
785 BOOST_CHECK_EQUAL( chain.IsArcEnd( 6 ), true );
786 BOOST_CHECK_EQUAL( chain.IsArcStart( 6 ), true );
787
788 // End index is not yet a shared point
789 int endIndex = chain.PointCount() - 1;
790 BOOST_CHECK_EQUAL( chain.IsSharedPt( endIndex ), false );
791 BOOST_CHECK_EQUAL( chain.IsArcEnd( endIndex ), true );
792 BOOST_CHECK_EQUAL( chain.IsArcStart( endIndex ), false );
793
794 for( int i = 0; i < chain.PointCount(); i++ )
795 {
796 BOOST_CHECK_EQUAL( chain.IsPtOnArc( i ), true ); // all points in the chain are arcs
797 }
798
799 // CLOSED CHAIN
800 chain.SetClosed( true );
801 BOOST_CHECK_EQUAL( chain.PointCount(), 12 ); // (-1) should have removed coincident points
802 //BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
803
804 // Start of the chain should be a shared point now, so can't be an arc end either
805 BOOST_CHECK_EQUAL( chain.IsSharedPt( 0 ), true );
806 BOOST_CHECK_EQUAL( chain.IsArcEnd( 0 ), true );
807 BOOST_CHECK_EQUAL( chain.IsArcStart( 0 ), true );
808
809 // Index 6 is the shared point between the two arcs in the middle of the chain
810 BOOST_CHECK_EQUAL( chain.IsSharedPt( 6 ), true );
811 BOOST_CHECK_EQUAL( chain.IsArcEnd( 6 ), true );
812 BOOST_CHECK_EQUAL( chain.IsArcStart( 6 ), true );
813
814 // End index is in the middle of an arc, so not an end point or shared point
815 endIndex = chain.PointCount() - 1;
816 BOOST_CHECK_EQUAL( chain.IsSharedPt( endIndex ), false );
817 BOOST_CHECK_EQUAL( chain.IsArcEnd( endIndex ), false );
818 BOOST_CHECK_EQUAL( chain.IsArcStart( endIndex ), false );
819}
820
821// Test SHAPE_LINE_CHAIN::Split()
823{
824 SEG seg1( VECTOR2I( 0, 100000 ), VECTOR2I( 50000, 0 ) );
825 SEG seg2( VECTOR2I( 200000, 0 ), VECTOR2I( 300000, 0 ) );
826 SHAPE_ARC arc( VECTOR2I( 200000, 0 ), VECTOR2I( 300000, 0 ), ANGLE_180 );
827
828 // Start a chain with 2 points (seg1)
829 SHAPE_LINE_CHAIN chain( { seg1.A, seg1.B } );
830 BOOST_CHECK_EQUAL( chain.PointCount(), 2 );
831 // Add first arc
832 chain.Append( arc );
833 BOOST_CHECK_EQUAL( chain.PointCount(), 9 );
834 // Add two points (seg2)
835 chain.Append( seg2.A );
836 chain.Append( seg2.B );
837 BOOST_CHECK_EQUAL( chain.PointCount(), 11 );
838 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
839
840 BOOST_TEST_CONTEXT( "Case 1: Point not in the chain" )
841 {
842 SHAPE_LINE_CHAIN chainCopy = chain;
843 BOOST_CHECK_EQUAL( chainCopy.Split( VECTOR2I( 400000, 0 ) ), -1 );
844 BOOST_CHECK_EQUAL( chainCopy.PointCount(), chain.PointCount() );
845 BOOST_CHECK_EQUAL( chainCopy.ArcCount(), chain.ArcCount() );
846 }
847
848 BOOST_TEST_CONTEXT( "Case 2: Point close to start of a segment" )
849 {
850 SHAPE_LINE_CHAIN chainCopy = chain;
851 VECTOR2I splitPoint = seg1.A + VECTOR2I( 5, -10 );
852 BOOST_CHECK_EQUAL( chainCopy.Split( splitPoint ), 1 );
853 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chainCopy ) );
854 BOOST_CHECK_EQUAL( chainCopy.GetPoint( 1 ), splitPoint );
855 BOOST_CHECK_EQUAL( chainCopy.PointCount(), chain.PointCount() + 1 ); // new point added
856 BOOST_CHECK_EQUAL( chainCopy.ArcCount(), chain.ArcCount() );
857 }
858
859 BOOST_TEST_CONTEXT( "Case 3: Point exactly on the segment" )
860 {
861 SHAPE_LINE_CHAIN chainCopy = chain;
862 VECTOR2I splitPoint = seg1.B;
863 BOOST_CHECK_EQUAL( chainCopy.Split( splitPoint ), 1 );
864 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chainCopy ) );
865 BOOST_CHECK_EQUAL( chainCopy.GetPoint( 1 ), splitPoint );
866 BOOST_CHECK_EQUAL( chainCopy.PointCount(), chain.PointCount() );
867 BOOST_CHECK_EQUAL( chainCopy.ArcCount(), chain.ArcCount() );
868 }
869
870 BOOST_TEST_CONTEXT( "Case 4: Point at start of arc" )
871 {
872 SHAPE_LINE_CHAIN chainCopy = chain;
873 VECTOR2I splitPoint = arc.GetP0();
874 BOOST_CHECK_EQUAL( chainCopy.Split( splitPoint ), 2 );
875 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chainCopy ) );
876 BOOST_CHECK_EQUAL( chainCopy.GetPoint( 2 ), splitPoint );
877 BOOST_CHECK_EQUAL( chainCopy.PointCount(), chain.PointCount() );
878 BOOST_CHECK_EQUAL( chainCopy.ArcCount(), chain.ArcCount() );
879 }
880
881 BOOST_TEST_CONTEXT( "Case 5: Point close to start of arc" )
882 {
883 SHAPE_LINE_CHAIN chainCopy = chain;
884 VECTOR2I splitPoint = arc.GetP0() + VECTOR2I( -10, 130 );
885 BOOST_CHECK_EQUAL( chainCopy.Split( splitPoint ), 3 );
886 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chainCopy ) );
887 BOOST_CHECK_EQUAL( chainCopy.GetPoint( 3 ), splitPoint );
888 BOOST_CHECK_EQUAL( chainCopy.IsSharedPt( 3 ), true ); // must be a shared point
889 BOOST_CHECK_EQUAL( chainCopy.PointCount(), chain.PointCount() + 1 ); // new point added
890 BOOST_CHECK_EQUAL( chainCopy.ArcCount(), chain.ArcCount() + 1 ); // new arc should have been created
891 }
892}
893
894
895// Test SHAPE_LINE_CHAIN::Slice()
897{
898 SEG targetSegment( VECTOR2I( 200000, 0 ), VECTOR2I( 300000, 0 ) );
899 SHAPE_ARC firstArc( VECTOR2I( 200000, 0 ), VECTOR2I( 300000, 0 ), ANGLE_180 );
900 SHAPE_ARC secondArc( VECTOR2I( -200000, -200000 ), VECTOR2I( -300000, -100000 ), -ANGLE_180 );
901 int tol = SHAPE_ARC::DefaultAccuracyForPCB(); // Tolerance for arc collisions
902
903 // Start a chain with 3 points
904 SHAPE_LINE_CHAIN chain( { VECTOR2I( 0, 0 ), VECTOR2I( 0, 100000 ), VECTOR2I( 100000, 0 ) } );
905 BOOST_CHECK_EQUAL( chain.PointCount(), 3 );
906 // Add first arc
907 chain.Append( firstArc );
908 BOOST_CHECK_EQUAL( chain.PointCount(), 10 );
909 // Add two points (target segment)
910 chain.Append( targetSegment.A );
911 chain.Append( targetSegment.B );
912 BOOST_CHECK_EQUAL( chain.PointCount(), 12 );
913 // Add a second arc
914 chain.Append( secondArc );
915 BOOST_CHECK_EQUAL( chain.PointCount(), 20 );
916 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
917
921 BOOST_TEST_CONTEXT( "Case 1: Start at arc endpoint, finish middle of arc" )
922 {
923 SHAPE_LINE_CHAIN sliceResult = chain.Slice( 9, 18 );
924 BOOST_CHECK( GEOM_TEST::IsOutlineValid( sliceResult ) );
925
926 BOOST_CHECK_EQUAL( sliceResult.ArcCount(), 1 );
927 SHAPE_ARC expectedSliceArc0;
928 expectedSliceArc0.ConstructFromStartEndCenter( secondArc.GetP0(), chain.GetPoint( 18 ),
929 secondArc.GetCenter(),
930 secondArc.IsClockwise() );
931
932 BOOST_CHECK_EQUAL( sliceResult.Arc( 0 ).GetP0(), expectedSliceArc0.GetP0() ); // equal arc start points
933 BOOST_CHECK( sliceResult.Arc( 0 ).Collide( expectedSliceArc0.GetArcMid(), tol ) );
934 BOOST_CHECK( sliceResult.Arc( 0 ).Collide( expectedSliceArc0.GetP1(), tol ) );
935
936 BOOST_CHECK_EQUAL( sliceResult.PointCount(), 10 );
937 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 0 ), firstArc.GetP1() ); // equal to arc end
938 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 1 ), targetSegment.A );
939 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 2 ), targetSegment.B );
940 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 3 ), expectedSliceArc0.GetP0() ); // equal to arc start
941 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( 3 ), true );
942
943 for( int i = 4; i <= 8; i++ )
944 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( i ), false );
945
946 for( int i = 3; i <= 7; i++ )
947 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( i ), false );
948
949 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( 9 ), true );
950 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 9 ), expectedSliceArc0.GetP1() ); // equal to arc end
951 }
952
956 BOOST_TEST_CONTEXT( "Case 2: Start at middle of an arc, finish at arc startpoint" )
957 {
958 SHAPE_LINE_CHAIN sliceResult = chain.Slice( 5, 12 );
959 BOOST_CHECK( GEOM_TEST::IsOutlineValid( sliceResult ) );
960
961 BOOST_CHECK_EQUAL( sliceResult.ArcCount(), 1 );
962 SHAPE_ARC expectedSliceArc0;
963 expectedSliceArc0.ConstructFromStartEndCenter( chain.GetPoint( 5 ), firstArc.GetP1(),
964 firstArc.GetCenter(),
965 firstArc.IsClockwise() );
966
967 BOOST_CHECK_EQUAL( sliceResult.Arc( 0 ).GetP1(),
968 expectedSliceArc0.GetP1() ); // equal arc end points
969 BOOST_CHECK( sliceResult.Arc( 0 ).Collide( expectedSliceArc0.GetArcMid(), tol ) );
970 BOOST_CHECK( sliceResult.Arc( 0 ).Collide( expectedSliceArc0.GetP0(), tol ) );
971
972 BOOST_CHECK_EQUAL( sliceResult.PointCount(), 8 );
973 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 0 ),
974 expectedSliceArc0.GetP0() ); // equal to arc start
975 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( 0 ), true );
976
977 for( int i = 1; i <= 4; i++ )
978 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( i ), false );
979
980 for( int i = 0; i <= 3; i++ )
981 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( i ), false );
982
983 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( 4 ), true );
984 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 4 ),
985 expectedSliceArc0.GetP1() ); // equal to arc end
986
987 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 5 ), targetSegment.A );
988 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 6 ), targetSegment.B );
989 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 7 ), secondArc.GetP0() );
990 }
991
995 BOOST_TEST_CONTEXT( "Case 3: Full arc, nothing else" )
996 {
997 SHAPE_LINE_CHAIN sliceResult = chain.Slice( 3, 9 );
998 BOOST_CHECK( GEOM_TEST::IsOutlineValid( sliceResult ) );
999
1000 BOOST_CHECK_EQUAL( sliceResult.ArcCount(), 1 );
1001 SHAPE_ARC sliceArc0 = sliceResult.Arc( 0 );
1002
1003 // Equal arc to original inserted arc
1004 BOOST_CHECK_EQUAL( firstArc.GetP1(), sliceArc0.GetP1() );
1005 BOOST_CHECK_EQUAL( firstArc.GetArcMid(), sliceArc0.GetArcMid() );
1006 BOOST_CHECK_EQUAL( firstArc.GetP1(), sliceArc0.GetP1() );
1007
1008 BOOST_CHECK_EQUAL( sliceResult.PointCount(), 7 );
1009 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 0 ), sliceArc0.GetP0() ); // equal to arc start
1010 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( 0 ), true );
1011
1012 for( int i = 1; i <= 6; i++ )
1013 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( i ), false );
1014
1015 for( int i = 0; i <= 5; i++ )
1016 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( i ), false );
1017
1018 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( 6 ), true );
1019 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 6 ), sliceArc0.GetP1() ); // equal to arc end
1020 }
1021
1025 BOOST_TEST_CONTEXT( "Case 4: Full arc, and straight segments to next arc start" )
1026 {
1027 SHAPE_LINE_CHAIN sliceResult = chain.Slice( 3, 12 );
1028 BOOST_CHECK( GEOM_TEST::IsOutlineValid( sliceResult ) );
1029
1030 BOOST_CHECK_EQUAL( sliceResult.ArcCount(), 1 );
1031 SHAPE_ARC sliceArc0 = sliceResult.Arc( 0 );
1032
1033 // Equal arc to original inserted arc
1034 BOOST_CHECK_EQUAL( firstArc.GetP1(), sliceArc0.GetP1() );
1035 BOOST_CHECK_EQUAL( firstArc.GetArcMid(), sliceArc0.GetArcMid() );
1036 BOOST_CHECK_EQUAL( firstArc.GetP1(), sliceArc0.GetP1() );
1037
1038 BOOST_CHECK_EQUAL( sliceResult.PointCount(), 10 );
1039 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 0 ), sliceArc0.GetP0() ); // equal to arc start
1040 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( 0 ), true );
1041
1042 for( int i = 1; i <= 6; i++ )
1043 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( i ), false );
1044
1045 for( int i = 0; i <= 5; i++ )
1046 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( i ), false );
1047
1048 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( 6 ), true );
1049 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 6 ), sliceArc0.GetP1() ); // equal to arc end
1050
1051 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 7 ), targetSegment.A );
1052 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 8 ), targetSegment.B );
1053 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 9 ), secondArc.GetP0() );
1054 }
1055
1056 BOOST_TEST_CONTEXT( "Case 5: Chain ends in arc and point" )
1057 {
1058 SHAPE_LINE_CHAIN chainCopy = chain;
1059 chainCopy.Append( VECTOR2I( 400000, 400000 ) );
1060
1061 SHAPE_LINE_CHAIN sliceResult = chainCopy.Slice( 11, -1 );
1062 BOOST_CHECK( GEOM_TEST::IsOutlineValid( sliceResult ) );
1063 BOOST_CHECK_EQUAL( sliceResult.GetPoint( -1 ), VECTOR2I( 400000, 400000 ) );
1064 }
1065
1066 BOOST_TEST_CONTEXT( "Case 6: Start to end, chain with one point" )
1067 {
1068 SHAPE_LINE_CHAIN chainCopy = SLC_CASES().OnePoint;
1069
1070 SHAPE_LINE_CHAIN sliceResult = chainCopy.Slice( 0, -1 );
1071 BOOST_CHECK_EQUAL( sliceResult.PointCount(), 1 );
1072 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 0 ), VECTOR2I( 233450000, 228360000 ) );
1073 BOOST_CHECK_EQUAL( sliceResult.GetPoint( -1 ), VECTOR2I( 233450000, 228360000 ) ); // Same as index 0
1074 }
1075
1076 BOOST_TEST_CONTEXT( "Case 7: Start to end, chain with two points" )
1077 {
1078 SHAPE_LINE_CHAIN chainCopy = SLC_CASES().TwoPoints;
1079
1080 SHAPE_LINE_CHAIN sliceResult = chainCopy.Slice( 0, -1 );
1081 BOOST_CHECK_EQUAL( sliceResult.PointCount(), 2 );
1082 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 0 ), VECTOR2I( 233450000, 228360000 ) );
1083 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 1 ), VECTOR2I( 263450000, 258360000 ) );
1084 BOOST_CHECK_EQUAL( sliceResult.GetPoint( -1 ), VECTOR2I( 263450000, 258360000 ) ); // Same as index 1
1085 }
1086
1087 BOOST_TEST_CONTEXT( "Case 8: Full 2nd arc, nothing else" )
1088 {
1089 SHAPE_LINE_CHAIN sliceResult = chain.Slice( 12, 19 );
1090 BOOST_CHECK( GEOM_TEST::IsOutlineValid( sliceResult ) );
1091
1092 BOOST_CHECK_EQUAL( sliceResult.ArcCount(), 1 );
1093 SHAPE_ARC sliceArc0 = sliceResult.Arc( 0 );
1094
1095 // Equal arc to original inserted arc
1096 BOOST_CHECK_EQUAL( secondArc.GetP1(), sliceArc0.GetP1() );
1097 BOOST_CHECK_EQUAL( secondArc.GetArcMid(), sliceArc0.GetArcMid() );
1098 BOOST_CHECK_EQUAL( secondArc.GetP1(), sliceArc0.GetP1() );
1099
1100 BOOST_CHECK_EQUAL( sliceResult.PointCount(), 8 );
1101 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 0 ), sliceArc0.GetP0() ); // equal to arc start
1102 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( 0 ), true );
1103
1104 for( int i = 1; i <= 7; i++ )
1105 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( i ), false );
1106
1107 for( int i = 0; i <= 6; i++ )
1108 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( i ), false );
1109
1110 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( 7 ), true );
1111 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 7 ), sliceArc0.GetP1() ); // equal to arc end
1112 }
1113
1114 BOOST_TEST_CONTEXT( "Case 9: Start at middle of a 2nd arc, finish at end" )
1115 {
1116 SHAPE_LINE_CHAIN sliceResult = chain.Slice( 16, 19 );
1117 BOOST_CHECK( GEOM_TEST::IsOutlineValid( sliceResult ) );
1118
1119 BOOST_CHECK_EQUAL( sliceResult.ArcCount(), 1 );
1120
1121 SHAPE_ARC expectedSliceArc0;
1122 expectedSliceArc0.ConstructFromStartEndCenter( chain.GetPoint( 16 ), secondArc.GetP1(),
1123 secondArc.GetCenter(),
1124 secondArc.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 BOOST_TEST_CONTEXT( "Case 10: New chain, start at arc middle, finish at end" )
1148 {
1149 SHAPE_LINE_CHAIN chain10;
1150 chain10.Append( firstArc );
1151
1152 SHAPE_LINE_CHAIN sliceResult = chain10.Slice( 3, 6 );
1153 BOOST_CHECK( GEOM_TEST::IsOutlineValid( sliceResult ) );
1154
1155 BOOST_CHECK_EQUAL( sliceResult.ArcCount(), 1 );
1156
1157 SHAPE_ARC expectedSliceArc0;
1158 expectedSliceArc0.ConstructFromStartEndCenter( chain10.GetPoint( 3 ), firstArc.GetP1(),
1159 firstArc.GetCenter(),
1160 firstArc.IsClockwise() );
1161
1162 BOOST_CHECK_EQUAL( sliceResult.Arc( 0 ).GetP1(),
1163 expectedSliceArc0.GetP1() ); // equal arc end points
1164 BOOST_CHECK( sliceResult.Arc( 0 ).Collide( expectedSliceArc0.GetArcMid(), tol ) );
1165 BOOST_CHECK( sliceResult.Arc( 0 ).Collide( expectedSliceArc0.GetP0(), tol ) );
1166
1167 BOOST_CHECK_EQUAL( sliceResult.PointCount(), 4 );
1168 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 0 ),
1169 expectedSliceArc0.GetP0() ); // equal to arc start
1170 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( 0 ), true );
1171
1172 for( int i = 1; i <= 3; i++ )
1173 BOOST_CHECK_EQUAL( sliceResult.IsArcStart( i ), false );
1174
1175 for( int i = 0; i <= 2; i++ )
1176 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( i ), false );
1177
1178 BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( 3 ), true );
1179 BOOST_CHECK_EQUAL( sliceResult.GetPoint( 3 ),
1180 expectedSliceArc0.GetP1() ); // equal to arc end
1181 }
1182}
1183
1184
1185// Test SHAPE_LINE_CHAIN::NearestPoint( VECTOR2I )
1186BOOST_AUTO_TEST_CASE( NearestPointPt )
1187{
1188 SEG seg1( VECTOR2I( 0, 100000 ), VECTOR2I( 50000, 0 ) );
1189 SEG seg2( VECTOR2I( 200000, 0 ), VECTOR2I( 300000, 0 ) );
1190 SHAPE_ARC arc( VECTOR2I( 200000, 0 ), VECTOR2I( 300000, 0 ), ANGLE_180 );
1191
1192 // Start a chain with 2 points (seg1)
1193 SHAPE_LINE_CHAIN chain( { seg1.A, seg1.B } );
1194 BOOST_CHECK_EQUAL( chain.PointCount(), 2 );
1195 // Add first arc
1196 chain.Append( arc );
1197 BOOST_CHECK_EQUAL( chain.PointCount(), 9 );
1198 // Add two points (seg2)
1199 chain.Append( seg2.A );
1200 chain.Append( seg2.B );
1201 BOOST_CHECK_EQUAL( chain.PointCount(), 11 );
1202 BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
1203
1204 VECTOR2I ptOnArcCloseToStart( 297553, 31697 ); //should be index 3 in chain
1205 VECTOR2I ptOnArcCloseToEnd( 139709, 82983 ); //should be index 6 in chain
1206
1207 BOOST_CHECK_EQUAL( chain.NearestPoint( ptOnArcCloseToStart, true ), ptOnArcCloseToStart );
1208 BOOST_CHECK_EQUAL( chain.NearestPoint( ptOnArcCloseToStart, false ), arc.GetP0() );
1209
1210 BOOST_CHECK_EQUAL( chain.NearestPoint( ptOnArcCloseToEnd, true ), ptOnArcCloseToEnd );
1211 BOOST_CHECK_EQUAL( chain.NearestPoint( ptOnArcCloseToEnd, false ), arc.GetP1() );
1212}
1213
1214
1215// Test SHAPE_LINE_CHAIN::Replace( SHAPE_LINE_CHAIN )
1217{
1218 BOOST_TEST_INFO( "8949 crash" );
1219
1220 std::vector<VECTOR2I> linePts = {
1221 { 206000000, 140110000 }, { 192325020, 140110000 }, { 192325020, 113348216 },
1222 { 192251784, 113274980 }, { 175548216, 113274980 }, { 175474980, 113348216 },
1223 { 175474980, 136694980 }, { 160774511, 121994511 }, { 160774511, 121693501 },
1224 { 160086499, 121005489 }, { 159785489, 121005489 }, { 159594511, 120814511 },
1225 { 160086499, 120814511 }, { 160774511, 120126499 }, { 160774511, 119153501 },
1226 { 160086499, 118465489 }, { 159113501, 118465489 }, { 158425489, 119153501 },
1227 { 158425489, 119645489 }, { 157325020, 118545020 }, { 157325020, 101925020 },
1228 { 208674980, 101925020 }, { 208674980, 145474980 }, { 192325020, 145474980 },
1229 { 192325020, 140110000 }
1230 };
1231
1232 SHAPE_LINE_CHAIN baseChain( linePts, false );
1233 baseChain.SetWidth( 250000 );
1234 BOOST_CHECK_EQUAL( baseChain.PointCount(), linePts.size() );
1235
1236 SHAPE_LINE_CHAIN replaceChain( { VECTOR2I( 192325020, 140110000 ) }, false );
1237 BOOST_CHECK_EQUAL( replaceChain.PointCount(), 1 );
1238
1239 baseChain.Replace( 1, 23, replaceChain );
1240
1241 BOOST_CHECK_EQUAL( baseChain.PointCount(), linePts.size() - ( 23 - 1 ) );
1242
1243 // Replacing the last point in a chain is special-cased
1244 baseChain.Replace( baseChain.PointCount() - 1, baseChain.PointCount() - 1, VECTOR2I( -1, -1 ) );
1245
1246 BOOST_CHECK_EQUAL( baseChain.CLastPoint(), VECTOR2I( -1, -1 ) );
1247}
1248
1249
Definition: seg.h:42
VECTOR2I A
Definition: seg.h:49
VECTOR2I B
Definition: seg.h:50
const VECTOR2I & GetArcMid() const
Definition: shape_arc.h:118
bool IsClockwise() const
Definition: shape_arc.h:317
SHAPE_ARC & ConstructFromStartEndCenter(const VECTOR2I &aStart, const VECTOR2I &aEnd, const VECTOR2I &aCenter, bool aClockwise=false, double aWidth=0)
Constructs this arc from the given start, end and center.
Definition: shape_arc.cpp:213
const VECTOR2I & GetP1() const
Definition: shape_arc.h:117
bool Collide(const SEG &aSeg, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if the boundary of shape (this) lies closer to the segment aSeg than aClearance,...
Definition: shape_arc.cpp:254
static double DefaultAccuracyForPCB()
Definition: shape_arc.h:276
const VECTOR2I & GetP0() const
Definition: shape_arc.h:116
const VECTOR2I & GetCenter() const
Definition: shape_arc.cpp:849
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
bool IsPtOnArc(size_t aPtIndex) const
const SHAPE_ARC & Arc(size_t aArc) const
bool IsClosed() const override
virtual const VECTOR2I GetPoint(int aIndex) const override
int Split(const VECTOR2I &aP, bool aExact=false)
Insert the point aP belonging to one of the our segments, splitting the adjacent segment in two.
int ShapeCount() const
Return the number of shapes (line segments or arcs) in this line chain.
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
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_AUTO_TEST_SUITE_END()
static const std::vector< CLOSE_TOGGLE_SHAPE_CASE > close_toggle_shape_cases
BOOST_AUTO_TEST_CASE(ClipperConstructorCase1)
static const std::vector< REMOVE_SHAPE_CASE > remove_shape_cases
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:695