KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_shape_poly_set_collision.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) 2017 CERN
5 * @author Alejandro GarcĂ­a Montoro <[email protected]>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21#include <tuple>
23
26
27#include "fixtures_geometry.h"
28
34{
35 // Structure to store the common data.
37
38 // Vectors containing colliding and non-colliding points
39 std::vector<VECTOR2I> collidingPoints, nonCollidingPoints;
40
41 // tuple of segment under test, collision result, and intersection point
42 typedef std::tuple<SEG, bool, VECTOR2I> SEG_CASE;
43
44 std::vector<SEG_CASE> segs;
45
50 {
51 // Create points colliding with the poly set.
52
53 // Inside the polygon
54 collidingPoints.emplace_back( 10, 90 );
55
56 // Inside the polygon, but on a re-entrant angle of a hole
57 collidingPoints.emplace_back( 15, 16 );
58
59 // On a hole edge => inside the polygon
60 collidingPoints.emplace_back( 40, 25 );
61
62 // On the outline edge => inside the polygon
63 collidingPoints.emplace_back( 0, 10 );
64
65 // Create points not colliding with the poly set.
66
67 // Completely outside of the polygon
68 nonCollidingPoints.emplace_back( 200, 200 );
69
70 // Inside the outline and inside a hole => outside the polygon
71 nonCollidingPoints.emplace_back( 15, 12 );
72
73 // Seg crossing the edge
74 segs.emplace_back( std::make_tuple( SEG( VECTOR2I( 90, 90 ), VECTOR2I( 110, 110 ) ),
75 true, VECTOR2I( 100, 100 ) ) );
76 segs.emplace_back( std::make_tuple( SEG( VECTOR2I( 110, 110 ), VECTOR2I( 90, 90 ) ),
77 true, VECTOR2I( 100, 100 ) ) );
78 segs.emplace_back( std::make_tuple( SEG( VECTOR2I( 50, -10 ), VECTOR2I( 50, 50 ) ),
79 true, VECTOR2I( 50, 0 ) ) );
80 segs.emplace_back( std::make_tuple( SEG( VECTOR2I( 50, 50 ), VECTOR2I( 50, -10 ) ),
81 true, VECTOR2I( 50, 0 ) ) );
82
83 // Seg fully inside
84 segs.emplace_back( std::make_tuple( SEG( VECTOR2I( 80, 80 ), VECTOR2I( 90, 90 ) ),
85 true, VECTOR2I( 85, 85 ) ) );
86 segs.emplace_back( std::make_tuple( SEG( VECTOR2I( 90, 90 ), VECTOR2I( 80, 80 ) ),
87 true, VECTOR2I( 85, 85 ) ) );
88
89 // Seg fully outside
90 segs.emplace_back( std::make_tuple( SEG( VECTOR2I( 110, 110 ), VECTOR2I( 120, 120 ) ),
91 false, VECTOR2I() ) );
92
93 // Seg touching
94 segs.emplace_back( std::make_tuple( SEG( VECTOR2I( 100, 100 ), VECTOR2I( 110, 110 ) ),
95 true, VECTOR2I( 100, 100 ) ) );
96 segs.emplace_back( std::make_tuple( SEG( VECTOR2I( 110, 110 ), VECTOR2I( 100, 100 ) ),
97 true, VECTOR2I( 100, 100 ) ) );
98 }
99
101 {
102 }
103};
104
108BOOST_FIXTURE_TEST_SUITE( SPSCollision, CollisionFixture )
109
110
114{
115 BOOST_CHECK( !common.solidPolySet.HasHoles() );
116 BOOST_CHECK( common.holeyPolySet.HasHoles() );
117}
118
124{
125 // Check points on corners
126 BOOST_CHECK( common.holeyPolySet.PointOnEdge( VECTOR2I( 0, 50 ) ) );
127
128 // Check points on outline edges
129 BOOST_CHECK( common.holeyPolySet.PointOnEdge( VECTOR2I( 0, 10 ) ) );
130
131 // Check points on hole edges
132 BOOST_CHECK( common.holeyPolySet.PointOnEdge( VECTOR2I( 10, 11 ) ) );
133
134 // Check points inside a hole -> not in edge
135 BOOST_CHECK( !common.holeyPolySet.PointOnEdge( VECTOR2I( 12, 12 ) ) );
136
137 // Check points inside the polygon and outside any hole -> not on edge
138 BOOST_CHECK( !common.holeyPolySet.PointOnEdge( VECTOR2I( 90, 90 ) ) );
139
140 // Check points outside the polygon -> not on edge
141 BOOST_CHECK( !common.holeyPolySet.PointOnEdge( VECTOR2I( 200, 200 ) ) );
142}
143
148BOOST_AUTO_TEST_CASE( pointInPolygonSet )
149{
150 // Check that the set contains the points that collide with it
151 for( const VECTOR2I& point : collidingPoints )
152 {
153 std::stringstream ss;
154 ss << "Point {" << point.x << ", " << point.y << " }";
155 BOOST_TEST_INFO( ss.str() );
156
157 BOOST_CHECK( common.holeyPolySet.Contains( point ) );
158 }
159
160 // Check that the set does not contain any point outside of it
161 for( const VECTOR2I& point : nonCollidingPoints )
162 {
163 std::stringstream ss;
164 ss << "Point {" << point.x << ", " << point.y << " }";
165 BOOST_TEST_INFO( ss.str() );
166
167 BOOST_CHECK( !common.holeyPolySet.Contains( point ) );
168 }
169}
170
175{
176 // When clearance = 0, the behaviour should be the same as with Contains
177
178 // Check that the set collides with the colliding points
179 for( const VECTOR2I& point : collidingPoints )
180 {
181 std::stringstream ss;
182 ss << "Point {" << point.x << ", " << point.y << " }";
183 BOOST_TEST_INFO( ss.str() );
184
185 BOOST_CHECK( common.holeyPolySet.Collide( point, 0 ) );
186 }
187
188 // Check that the set does not collide with the non colliding points
189 for( const VECTOR2I& point : nonCollidingPoints )
190 {
191 std::stringstream ss;
192 ss << "Point {" << point.x << ", " << point.y << " }";
193 BOOST_TEST_INFO( ss.str() );
194
195 BOOST_CHECK( !common.holeyPolySet.Collide( point, 0 ) );
196 }
197
198 // Checks with clearance > 0
199
200 // Point at the offset zone outside of the outline => collision!
201 BOOST_CHECK( common.holeyPolySet.Collide( VECTOR2I( -1, 10 ), 5 ) );
202
203 // Point at the offset zone outside of a hole => collision!
204 BOOST_CHECK( common.holeyPolySet.Collide( VECTOR2I( 11, 11 ), 5 ) );
205}
206
211BOOST_AUTO_TEST_CASE( CollideVertex )
212{
213 // Check that the set collides with the colliding points
214 for( const VECTOR2I& point : common.holeyPoints )
215 {
216 BOOST_CHECK_MESSAGE( common.holeyPolySet.CollideVertex( point, nullptr, 0 ),
217 " Point " << point.x << ", " << point.y <<
218 " does not collide with holeyPolySet polygon" );
219 }
220}
221
226BOOST_AUTO_TEST_CASE( CollideVertexWithClearance )
227{
228 // Check that the set collides with the colliding points
229 for( const VECTOR2I& point : common.holeyPoints )
230 BOOST_CHECK( common.holeyPolySet.CollideVertex( point + VECTOR2I( 1, 1 ), nullptr, 2 ) );
231}
232
233
237BOOST_AUTO_TEST_CASE( CollideSegments )
238{
239 for( const SEG_CASE& testCase : segs )
240 {
241 SEG seg;
242 bool expectedResult;
243 VECTOR2I expectedLocation;
244
245 std::tie( seg, expectedResult, expectedLocation ) = testCase;
246
248
249 BOOST_CHECK( common.holeyPolySet.Collide( seg, 0, nullptr, &location ) == expectedResult );
250
251 if( expectedResult )
252 BOOST_REQUIRE_EQUAL( location, expectedLocation );
253 }
254}
255
256// regression for keepout collision location reported at the origin
257BOOST_AUTO_TEST_CASE( CollideSegmentLocationNearMiss )
258{
260 SHAPE_LINE_CHAIN outline;
261 outline.Append( 1000, 1000 );
262 outline.Append( 2000, 1000 );
263 outline.Append( 2000, 2000 );
264 outline.Append( 1000, 2000 );
265 outline.SetClosed( true );
266 square.AddOutline( outline );
267
268 const int clearance = 100;
269
270 // first segment sits outside the first iterated edge
271 std::vector<SEG> nearMisses = {
272 SEG( VECTOR2I( 1400, 950 ), VECTOR2I( 1600, 950 ) ),
273 SEG( VECTOR2I( 1400, 2050 ), VECTOR2I( 1600, 2050 ) ),
274 SEG( VECTOR2I( 950, 1400 ), VECTOR2I( 950, 1600 ) ),
275 SEG( VECTOR2I( 2050, 1400 ), VECTOR2I( 2050, 1600 ) ),
276 };
277
278 for( const SEG& seg : nearMisses )
279 {
280 BOOST_TEST_CONTEXT( "seg " << seg.A << " -> " << seg.B )
281 {
282 int actual = -1;
283 VECTOR2I location( -1, -1 );
284
285 BOOST_CHECK( square.Collide( seg, clearance, &actual, &location ) );
286 BOOST_CHECK( location != VECTOR2I( 0, 0 ) );
287 BOOST_CHECK( square.PointOnEdge( location ) );
289 }
290 }
291}
292
double square(double x)
Definition seg.h:38
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
Represent a set of closed polygons.
static bool Collide(const SHAPE_CIRCLE &aA, const SHAPE_CIRCLE &aB, int aClearance, int *aActual, VECTOR2I *aLocation, VECTOR2I *aMTV)
Fixture for the Collision test suite.
struct KI_TEST::CommonTestData common
std::tuple< SEG, bool, VECTOR2I > SEG_CASE
std::vector< VECTOR2I > collidingPoints
std::vector< VECTOR2I > nonCollidingPoints
std::vector< SEG_CASE > segs
Common data for some of the SHAPE_POLY_SET tests:
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE_END()
BOOST_TEST_INFO("Two-port Series .op current = "<< iDevice)
BOOST_CHECK_MESSAGE(totalMismatches==0, std::to_string(totalMismatches)+" board(s) with strategy disagreements")
BOOST_TEST_CONTEXT("Test Clearance")
int clearance
VECTOR2I location
int actual
BOOST_AUTO_TEST_CASE(HasHoles)
Declares the CollisionFixture as the boost test suite fixture.
BOOST_CHECK_EQUAL(result, "25.4")
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683