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, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-3.0.html
19 * or you may search the http://www.gnu.org website for the version 3 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#ifndef POLY_CONTAINMENT_INDEX_H
25#define POLY_CONTAINMENT_INDEX_H
26
27#include <climits>
28#include <cstdint>
29#include <vector>
30
32#include <geometry/seg.h>
34#include <math/util.h>
35#include <math/vector2d.h>
36
50{
51public:
53
60 void Build( const SHAPE_POLY_SET& aPolySet )
61 {
62 m_outlineCount = aPolySet.OutlineCount();
63
65
66 for( int outlineIdx = 0; outlineIdx < m_outlineCount; outlineIdx++ )
67 {
68 const SHAPE_LINE_CHAIN& outline = aPolySet.COutline( outlineIdx );
69 int ptCount = outline.PointCount();
70
71 if( ptCount < 3 )
72 continue;
73
74 for( int j = 0; j < ptCount; j++ )
75 {
76 const VECTOR2I& p1 = outline.CPoint( j );
77 const VECTOR2I& p2 = outline.CPoint( ( j + 1 ) % ptCount );
78
79 intptr_t idx = static_cast<intptr_t>( m_segments.size() );
80 m_segments.push_back( { p1, p2, outlineIdx } );
81
82 int min[2] = { std::min( p1.x, p2.x ), std::min( p1.y, p2.y ) };
83 int max[2] = { std::max( p1.x, p2.x ), std::max( p1.y, p2.y ) };
84 builder.Add( min, max, idx );
85 }
86 }
87
88 m_tree = builder.Build();
89 }
90
104 bool Contains( const VECTOR2I& aPt, int aAccuracy = 0 ) const
105 {
106 if( m_segments.empty() )
107 return false;
108
109 // Most polygon sets have very few outlines, so use a stack buffer to avoid
110 // per-query heap allocation.
111 int crossingsStack[8] = {};
112 int* crossings = crossingsStack;
113 std::vector<int> crossingsHeap;
114
115 if( m_outlineCount > 8 )
116 {
117 crossingsHeap.resize( m_outlineCount, 0 );
118 crossings = crossingsHeap.data();
119 }
120
121 // Only segments whose X extent reaches past aPt.x can produce a rightward ray crossing.
122 int searchMin[2] = { aPt.x, aPt.y };
123 int searchMax[2] = { INT_MAX, aPt.y };
124
125 auto rayCrossVisitor = [&]( intptr_t idx ) -> bool
126 {
127 const EDGE& seg = m_segments[idx];
128 const VECTOR2I& p1 = seg.p1;
129 const VECTOR2I& p2 = seg.p2;
130
131 if( ( p1.y >= aPt.y ) == ( p2.y >= aPt.y ) )
132 return true;
133
134 const VECTOR2I diff = p2 - p1;
135 const int d = rescale( diff.x, ( aPt.y - p1.y ), diff.y );
136
137 if( aPt.x - p1.x < d )
138 crossings[seg.outlineIdx]++;
139
140 return true;
141 };
142
143 m_tree.Search( searchMin, searchMax, rayCrossVisitor );
144
145 for( int i = 0; i < m_outlineCount; i++ )
146 {
147 if( crossings[i] & 1 )
148 return true;
149 }
150
151 if( aAccuracy > 1 )
152 {
153 int edgeMin[2] = { aPt.x - aAccuracy, aPt.y - aAccuracy };
154 int edgeMax[2] = { aPt.x + aAccuracy, aPt.y + aAccuracy };
155 SEG::ecoord accuracySq = SEG::Square( aAccuracy );
156 bool onEdge = false;
157
158 auto edgeDistVisitor = [&]( intptr_t idx ) -> bool
159 {
160 const EDGE& seg = m_segments[idx];
161 SEG s( seg.p1, seg.p2 );
162
163 if( s.SquaredDistance( aPt ) <= accuracySq )
164 {
165 onEdge = true;
166 return false;
167 }
168
169 return true;
170 };
171
172 m_tree.Search( edgeMin, edgeMax, edgeDistVisitor );
173
174 return onEdge;
175 }
176
177 return false;
178 }
179
180private:
181 struct EDGE
182 {
186 };
187
188 std::vector<EDGE> m_segments;
191};
192
193#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:42
ecoord SquaredDistance(const SEG &aSeg) const
Definition seg.cpp:80
VECTOR2I::extended_type ecoord
Definition seg.h:44
static SEG::ecoord Square(int a)
Definition seg.h:123
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:139
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:687