KiCad PCB EDA Suite
Loading...
Searching...
No Matches
poly_containment_index.h
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 3
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, see <https://www.gnu.org/licenses/>.
18 */
19
20#ifndef POLY_CONTAINMENT_INDEX_H
21#define POLY_CONTAINMENT_INDEX_H
22
23#include <climits>
24#include <cstdint>
25#include <vector>
26
28#include <geometry/seg.h>
30#include <math/util.h>
31#include <math/vector2d.h>
32
46{
47public:
49
56 void Build( const SHAPE_POLY_SET& aPolySet )
57 {
58 m_outlineCount = aPolySet.OutlineCount();
59
61
62 for( int outlineIdx = 0; outlineIdx < m_outlineCount; outlineIdx++ )
63 {
64 const SHAPE_LINE_CHAIN& outline = aPolySet.COutline( outlineIdx );
65 int ptCount = outline.PointCount();
66
67 if( ptCount < 3 )
68 continue;
69
70 for( int j = 0; j < ptCount; j++ )
71 {
72 const VECTOR2I& p1 = outline.CPoint( j );
73 const VECTOR2I& p2 = outline.CPoint( ( j + 1 ) % ptCount );
74
75 intptr_t idx = static_cast<intptr_t>( m_segments.size() );
76 m_segments.push_back( { p1, p2, outlineIdx } );
77
78 int min[2] = { std::min( p1.x, p2.x ), std::min( p1.y, p2.y ) };
79 int max[2] = { std::max( p1.x, p2.x ), std::max( p1.y, p2.y ) };
80 builder.Add( min, max, idx );
81 }
82 }
83
84 m_tree = builder.Build();
85 }
86
100 bool Contains( const VECTOR2I& aPt, int aAccuracy = 0 ) const
101 {
102 if( m_segments.empty() )
103 return false;
104
105 // Most polygon sets have very few outlines, so use a stack buffer to avoid
106 // per-query heap allocation.
107 int crossingsStack[8] = {};
108 int* crossings = crossingsStack;
109 std::vector<int> crossingsHeap;
110
111 if( m_outlineCount > 8 )
112 {
113 crossingsHeap.resize( m_outlineCount, 0 );
114 crossings = crossingsHeap.data();
115 }
116
117 // Only segments whose X extent reaches past aPt.x can produce a rightward ray crossing.
118 int searchMin[2] = { aPt.x, aPt.y };
119 int searchMax[2] = { INT_MAX, aPt.y };
120
121 auto rayCrossVisitor = [&]( intptr_t idx ) -> bool
122 {
123 const EDGE& seg = m_segments[idx];
124 const VECTOR2I& p1 = seg.p1;
125 const VECTOR2I& p2 = seg.p2;
126
127 if( ( p1.y >= aPt.y ) == ( p2.y >= aPt.y ) )
128 return true;
129
130 const VECTOR2I diff = p2 - p1;
131 const int d = rescale( diff.x, ( aPt.y - p1.y ), diff.y );
132
133 if( aPt.x - p1.x < d )
134 crossings[seg.outlineIdx]++;
135
136 return true;
137 };
138
139 m_tree.Search( searchMin, searchMax, rayCrossVisitor );
140
141 for( int i = 0; i < m_outlineCount; i++ )
142 {
143 if( crossings[i] & 1 )
144 return true;
145 }
146
147 if( aAccuracy > 1 )
148 {
149 int edgeMin[2] = { aPt.x - aAccuracy, aPt.y - aAccuracy };
150 int edgeMax[2] = { aPt.x + aAccuracy, aPt.y + aAccuracy };
151 SEG::ecoord accuracySq = SEG::Square( aAccuracy );
152 bool onEdge = false;
153
154 auto edgeDistVisitor = [&]( intptr_t idx ) -> bool
155 {
156 const EDGE& seg = m_segments[idx];
157 SEG s( seg.p1, seg.p2 );
158
159 if( s.SquaredDistance( aPt ) <= accuracySq )
160 {
161 onEdge = true;
162 return false;
163 }
164
165 return true;
166 };
167
168 m_tree.Search( edgeMin, edgeMax, edgeDistVisitor );
169
170 return onEdge;
171 }
172
173 return false;
174 }
175
176private:
177 struct EDGE
178 {
182 };
183
184 std::vector<EDGE> m_segments;
187};
188
189#endif // POLY_CONTAINMENT_INDEX_H
Builder for constructing a PACKED_RTREE from a set of items.
void Add(const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS], const DATATYPE &aData)
Static (immutable) packed R-tree built via Hilbert-curve bulk loading.
void Build(const SHAPE_POLY_SET &aPolySet)
Build the spatial index from a SHAPE_POLY_SET's outlines.
POLY_CONTAINMENT_INDEX()=default
KIRTREE::PACKED_RTREE< intptr_t, int, 2 > m_tree
bool Contains(const VECTOR2I &aPt, int aAccuracy=0) const
Test whether a point is inside the indexed polygon set.
Definition seg.h:38
ecoord SquaredDistance(const SEG &aSeg) const
Definition seg.cpp:76
VECTOR2I::extended_type ecoord
Definition seg.h:40
static SEG::ecoord Square(int a)
Definition seg.h:119
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
int PointCount() const
Return the number of points (vertices) in this line chain.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
Represent a set of closed polygons.
int OutlineCount() const
Return the number of outlines in the set.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
T rescale(T aNumerator, T aValue, T aDenominator)
Scale a number (value) by rational (numerator/denominator).
Definition util.h:135
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683