KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_segment_index.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 modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * 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, see <https://www.gnu.org/licenses/>.
18 */
19
20#include <boost/test/unit_test.hpp>
21
23
24#include <algorithm>
25#include <limits>
26#include <vector>
27
28
29BOOST_AUTO_TEST_SUITE( SegmentIndex )
30
31
32static std::vector<int> candidates( const SEGMENT_INDEX& aIndex, const SEG& aQuery, int aPadding )
33{
34 std::vector<int> result;
35 auto visitor = [&]( int aItem )
36 {
37 result.push_back( aItem );
38 return true;
39 };
40
41 aIndex.VisitCandidates( aQuery, aPadding, visitor );
42 std::sort( result.begin(), result.end() );
43 return result;
44}
45
46
47static bool endpointBoundsOverlap( const SEG& aItem, const SEG& aQuery, int aPadding )
48{
49 const int64_t queryMinX = static_cast<int64_t>( std::min( aQuery.A.x, aQuery.B.x ) ) - aPadding;
50 const int64_t queryMinY = static_cast<int64_t>( std::min( aQuery.A.y, aQuery.B.y ) ) - aPadding;
51 const int64_t queryMaxX = static_cast<int64_t>( std::max( aQuery.A.x, aQuery.B.x ) ) + aPadding;
52 const int64_t queryMaxY = static_cast<int64_t>( std::max( aQuery.A.y, aQuery.B.y ) ) + aPadding;
53 const int64_t itemMinX = std::min( aItem.A.x, aItem.B.x );
54 const int64_t itemMinY = std::min( aItem.A.y, aItem.B.y );
55 const int64_t itemMaxX = std::max( aItem.A.x, aItem.B.x );
56 const int64_t itemMaxY = std::max( aItem.A.y, aItem.B.y );
57
58 return itemMaxX >= queryMinX && itemMinX <= queryMaxX && itemMaxY >= queryMinY && itemMinY <= queryMaxY;
59}
60
61
62BOOST_AUTO_TEST_CASE( EmptyAndDegenerateSegments )
63{
64 SEGMENT_INDEX empty( {} );
65 BOOST_CHECK( candidates( empty, SEG( { 0, 0 }, { 1, 1 } ), 0 ).empty() );
66
67 std::vector<SEG> segments = { SEG( { 5, 5 }, { 5, 5 } ), SEG( { 5, 5 }, { 5, 5 } ), SEG( { 20, 20 }, { 30, 30 } ) };
68 SEGMENT_INDEX index( segments );
69
70 BOOST_CHECK_EQUAL( index.size(), 3 );
71 BOOST_CHECK( candidates( index, SEG( { 5, 5 }, { 5, 5 } ), 0 ) == std::vector<int>( { 0, 1 } ) );
72 BOOST_CHECK( index.Segment( 2 ) == SEG( { 20, 20 }, { 30, 30 } ) );
73}
74
75
76BOOST_AUTO_TEST_CASE( SaturatesPaddedQueryBounds )
77{
78 constexpr int min = std::numeric_limits<int>::min();
79 constexpr int max = std::numeric_limits<int>::max();
80
81 std::vector<SEG> segments = { SEG( { min, min }, { min + 1, min + 1 } ), SEG( { max - 1, max - 1 }, { max, max } ),
82 SEG( { -1, -1 }, { 1, 1 } ) };
83 SEGMENT_INDEX index( segments );
84
85 BOOST_CHECK( candidates( index, SEG( { min + 1, min + 1 }, { min + 1, min + 1 } ), max )
86 == std::vector<int>( { 0, 2 } ) );
87 BOOST_CHECK( candidates( index, SEG( { max - 1, max - 1 }, { max - 1, max - 1 } ), max )
88 == std::vector<int>( { 1, 2 } ) );
89
90 const std::vector<SEG> queries = { SEG( { min, min }, { min, min } ),
91 SEG( { min + 1, max - 1 }, { min + 1, max - 1 } ), SEG( { -1, -1 }, { 1, 1 } ),
92 SEG( { max, max }, { max, max } ) };
93
94 for( int padding : { 0, 1, max } )
95 {
96 for( const SEG& query : queries )
97 {
98 std::vector<int> expected;
99
100 for( size_t i = 0; i < segments.size(); ++i )
101 {
102 if( endpointBoundsOverlap( segments[i], query, padding ) )
103 expected.push_back( static_cast<int>( i ) );
104 }
105
106 BOOST_CHECK( candidates( index, query, padding ) == expected );
107 }
108 }
109}
110
111
112BOOST_AUTO_TEST_CASE( NegativePaddingMatchesZero )
113{
114 constexpr int min = std::numeric_limits<int>::min();
115
116 SEGMENT_INDEX index( { SEG( { 0, 0 }, { 10, 0 } ), SEG( { 100, 0 }, { 110, 0 } ) } );
117 const SEG query( { 5, 0 }, { 5, 0 } );
118
119 // Unclamped negative padding inverts the query rect, which matches nothing at all
120 BOOST_CHECK( candidates( index, query, -1 ) == std::vector<int>( { 0 } ) );
121 BOOST_CHECK( candidates( index, query, min ) == std::vector<int>( { 0 } ) );
122}
123
124
int index
Immutable owning spatial snapshot of straight segments.
Definition seg.h:38
VECTOR2I A
Definition seg.h:45
VECTOR2I B
Definition seg.h:46
static bool empty(const wxTextEntryBase *aCtrl)
STL namespace.
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_AUTO_TEST_SUITE_END()
VECTOR3I expected(15, 30, 45)
static std::vector< int > candidates(const SEGMENT_INDEX &aIndex, const SEG &aQuery, int aPadding)
static bool endpointBoundsOverlap(const SEG &aItem, const SEG &aQuery, int aPadding)
BOOST_AUTO_TEST_CASE(EmptyAndDegenerateSegments)
wxString result
Test unit parsing edge cases and error handling.
BOOST_CHECK_EQUAL(result, "25.4")