KiCad PCB EDA Suite
Loading...
Searching...
No Matches
shape_poly_tri_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 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, see <https://www.gnu.org/licenses/>.
18 */
19
20#ifndef SHAPE_POLY_TRI_INDEX_H
21#define SHAPE_POLY_TRI_INDEX_H
22
23#include <cstdint>
24#include <deque>
25#include <limits>
26#include <vector>
27#include <utility>
28
29#include <math/box2.h>
32
41{
42public:
44
46 explicit TRIANGULATION_INDEX( const std::vector<std::unique_ptr<SHAPE_POLY_SET::TRIANGULATED_POLYGON>>& aPolys )
47 {
48 size_t count = 0;
49
50 for( const std::unique_ptr<SHAPE_POLY_SET::TRIANGULATED_POLYGON>& poly : aPolys )
51 count += poly->GetTriangleCount();
52
53 if( count == 0 )
54 return;
55
56 m_tris.reserve( count );
57
59 builder.Reserve( count );
60
61 for( const std::unique_ptr<SHAPE_POLY_SET::TRIANGULATED_POLYGON>& poly : aPolys )
62 {
63 for( const TRI& tri : poly->Triangles() )
64 {
65 const BOX2I bbox = tri.BBox();
66 const int lo[2] = { bbox.GetX(), bbox.GetY() };
67 const int hi[2] = { bbox.GetRight(), bbox.GetBottom() };
68
69 builder.Add( lo, hi, static_cast<uint32_t>( m_tris.size() ) );
70 m_tris.push_back( &tri );
71 }
72 }
73
74 m_tree = builder.Build();
75 }
76
81 template <typename VISITOR>
82 void Query( const BOX2I& aBox, VISITOR aVisitor ) const
83 {
84 if( m_tris.empty() )
85 return;
86
87 const int lo[2] = { aBox.GetX(), aBox.GetY() };
88 const int hi[2] = { aBox.GetRight(), aBox.GetBottom() };
89
90 // PACKED_RTREE::Search takes its visitor by non-const reference, so name it.
91 auto forward = [&]( uint32_t aIndex ) -> bool
92 {
93 return aVisitor( m_tris[aIndex] );
94 };
95
96 m_tree.Search( lo, hi, forward );
97 }
98
99private:
101
103 std::vector<const TRI*> m_tris;
104};
105
106
116template <typename VISITOR>
118 const std::vector<std::unique_ptr<SHAPE_POLY_SET::TRIANGULATED_POLYGON>>& aPolys,
119 const BOX2I& aBox, VISITOR aVisitor )
120{
121 if( aIndex )
122 {
123 bool stopped = false;
124
125 aIndex->Query( aBox,
127 {
128 if( aVisitor( aTri ) )
129 return true;
130
131 stopped = true;
132 return false;
133 } );
134
135 return !stopped;
136 }
137
138 for( const std::unique_ptr<SHAPE_POLY_SET::TRIANGULATED_POLYGON>& poly : aPolys )
139 {
140 for( const SHAPE_POLY_SET::TRIANGULATED_POLYGON::TRI& tri : poly->Triangles() )
141 {
142 if( !aVisitor( &tri ) )
143 return false;
144 }
145 }
146
147 return true;
148}
149
150
157inline bool AnyTriangleHit( const TRIANGULATION_INDEX* aIndex,
158 const std::vector<std::unique_ptr<SHAPE_POLY_SET::TRIANGULATED_POLYGON>>& aPolys,
159 const SHAPE* aShape, int aClearance = 0, int* aActual = nullptr,
160 VECTOR2I* aLocation = nullptr )
161{
162 // NOT BBox( aClearance ): SHAPE_COMPOUND::BBox() ignores its argument, and inflating
163 // separately keeps near-miss triangles in the candidate set.
164 BOX2I qbox = aShape->BBox();
165 if( aClearance > 0 )
166 {
167 qbox.Inflate( aClearance );
168 }
169
170 if( !aActual && !aLocation )
171 {
172 return !VisitTriangleCandidates( aIndex, aPolys, qbox,
174 {
175 return !aShape->Collide( aTri, aClearance );
176 } );
177 }
178
179 int actual = std::numeric_limits<int>::max();
181
182 VisitTriangleCandidates( aIndex, aPolys, qbox,
184 {
185 int triActual;
186 VECTOR2I triLocation;
187
188 if( aShape->Collide( aTri, aClearance, &triActual, &triLocation )
189 && triActual < actual )
190 {
191 actual = triActual;
192 location = triLocation;
193 }
194
195 return true; // Finding a minimum needs every candidate
196 } );
197
198 if( actual == std::numeric_limits<int>::max() )
199 return false;
200
201 if( aActual )
202 *aActual = actual;
203
204 if( aLocation )
205 *aLocation = location;
206
207 return true;
208}
209
210
212inline bool AnyTriangleHit( const TRIANGULATION_INDEX* aIndex,
213 const std::vector<std::unique_ptr<SHAPE_POLY_SET::TRIANGULATED_POLYGON>>& aPolys,
214 const VECTOR2I& aPt )
215{
216 return !VisitTriangleCandidates( aIndex, aPolys, BOX2I( aPt, VECTOR2I( 0, 0 ) ),
218 {
219 return !aTri->Collide( aPt );
220 } );
221}
222
223#endif // SHAPE_POLY_TRI_INDEX_H
BOX2< VECTOR2I > BOX2I
Definition box2.h:914
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:553
constexpr coord_type GetY() const
Definition box2.h:205
constexpr coord_type GetX() const
Definition box2.h:204
constexpr coord_type GetRight() const
Definition box2.h:214
constexpr coord_type GetBottom() const
Definition box2.h:219
Builder for constructing a PACKED_RTREE from a set of items.
void Add(const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS], const DATATYPE &aData)
void Reserve(size_t aCount)
Static (immutable) packed R-tree built via Hilbert-curve bulk loading.
virtual bool Collide(const VECTOR2I &aP, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if point aP lies closer to us than aClearance.
An abstract shape on 2D plane.
Definition shape.h:124
virtual bool Collide(const VECTOR2I &aP, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const
Check if the boundary of shape (this) lies closer to the point aP than aClearance,...
Definition shape.h:181
virtual const BOX2I BBox(int aClearance=0) const =0
Compute a bounding box of the shape, with a margin of aClearance a collision.
A spatial index over the triangles of a cached triangulation, used to prune collision tests.
KIRTREE::PACKED_RTREE< uint32_t, int, 2 > m_tree
std::vector< const TRI * > m_tris
Not owning: the triangulation outlives us.
SHAPE_POLY_SET::TRIANGULATED_POLYGON::TRI TRI
TRIANGULATION_INDEX(const std::vector< std::unique_ptr< SHAPE_POLY_SET::TRIANGULATED_POLYGON > > &aPolys)
Index every triangle of every polygon. Immutable once constructed.
void Query(const BOX2I &aBox, VISITOR aVisitor) const
Visit every triangle whose bounding box overlaps aBox.
bool AnyTriangleHit(const TRIANGULATION_INDEX *aIndex, const std::vector< std::unique_ptr< SHAPE_POLY_SET::TRIANGULATED_POLYGON > > &aPolys, const SHAPE *aShape, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr)
Return true if any candidate triangle collides with aShape within aClearance.
bool VisitTriangleCandidates(const TRIANGULATION_INDEX *aIndex, const std::vector< std::unique_ptr< SHAPE_POLY_SET::TRIANGULATED_POLYGON > > &aPolys, const BOX2I &aBox, VISITOR aVisitor)
Visit the triangles that could collide with something inside aBox, through aIndex when one exists,...
VECTOR2I location
int actual
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708