KiCad PCB EDA Suite
Loading...
Searching...
No Matches
bbox_2d.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) 2015-2016 Mario Luzeiro <[email protected]>
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
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
25
26#include "3d_fastmath.h"
27
28#include "bbox_2d.h"
29#include "../ray.h"
30#include <wx/debug.h>
31
32
34{
35 Reset();
36}
37
38
39BBOX_2D::BBOX_2D( const SFVEC2F& aPbInit )
40{
41 m_min = aPbInit;
42 m_max = aPbInit;
43}
44
45
46BBOX_2D::BBOX_2D( const SFVEC2F& aPbMin, const SFVEC2F& aPbMax )
47{
48 Set( aPbMin, aPbMax );
49}
50
51
55
56
57void BBOX_2D::Set( const SFVEC2F& aPbMin, const SFVEC2F& aPbMax )
58{
59 m_min.x = fminf( aPbMin.x, aPbMax.x );
60 m_min.y = fminf( aPbMin.y, aPbMax.y );
61
62 m_max.x = fmaxf( aPbMin.x, aPbMax.x );
63 m_max.y = fmaxf( aPbMin.y, aPbMax.y );
64}
65
66
67void BBOX_2D::Set( const BBOX_2D& aBBox )
68{
69 wxASSERT( aBBox.IsInitialized() );
70
71 Set( aBBox.Min(), aBBox.Max() );
72}
73
74
76{
77 return !( ( FLT_MAX == m_min.x ) || ( FLT_MAX == m_min.y ) || ( -FLT_MAX == m_max.x )
78 || ( -FLT_MAX == m_max.y ) );
79}
80
81
83{
84 m_min = SFVEC2F( FLT_MAX, FLT_MAX );
85 m_max = SFVEC2F( -FLT_MAX,-FLT_MAX );
86}
87
88
89void BBOX_2D::Union( const SFVEC2F& aPoint )
90{
91 // get the minimum value between the added point and the existent bounding box
92 m_min.x = fminf( m_min.x, aPoint.x );
93 m_min.y = fminf( m_min.y, aPoint.y );
94
95 // get the maximum value between the added point and the existent bounding box
96 m_max.x = fmaxf( m_max.x, aPoint.x );
97 m_max.y = fmaxf( m_max.y, aPoint.y );
98}
99
100
101void BBOX_2D::Union( const BBOX_2D& aBBox )
102{
103 // get the minimum value between the added bounding box and
104 // the existent bounding box
105 m_min.x = fminf( m_min.x, aBBox.m_min.x );
106 m_min.y = fminf( m_min.y, aBBox.m_min.y );
107
108 // get the maximum value between the added bounding box and
109 // the existent bounding box
110 m_max.x = fmaxf( m_max.x, aBBox.m_max.x );
111 m_max.y = fmaxf( m_max.y, aBBox.m_max.y );
112}
113
114
116{
117 return ( m_max + m_min ) * 0.5f;
118}
119
120
122{
123 return m_max - m_min;
124}
125
126
127unsigned int BBOX_2D::MaxDimension() const
128{
129 unsigned int result = 0;
130 const SFVEC2F extent = GetExtent();
131
132 if( extent.y > extent.x ) result = 1;
133
134 return result;
135}
136
137
139{
140 const SFVEC2F extent = GetExtent();
141
142 return 2.0f * ( extent.x + extent.y );
143}
144
145
146void BBOX_2D::Scale( float aScale )
147{
148 wxASSERT( IsInitialized() );
149
150 const SFVEC2F scaleV( aScale, aScale );
151 const SFVEC2F centerV = GetCenter();
152
153 m_min = ( m_min - centerV ) * scaleV + centerV;
154 m_max = ( m_max - centerV ) * scaleV + centerV;
155}
156
157
159{
160 m_min.x = NextFloatDown( m_min.x );
161 m_min.y = NextFloatDown( m_min.y );
162
163 m_max.x = NextFloatUp( m_max.x );
164 m_max.y = NextFloatUp( m_max.y );
165}
166
167
169{
170 m_min.x = NextFloatUp( m_min.x );
171 m_min.y = NextFloatUp( m_min.y );
172
173 m_max.x = NextFloatDown( m_max.x );
174 m_max.y = NextFloatDown( m_max.y );
175}
176
177
178// http://goanna.cs.rmit.edu.au/~gl/teaching/rtr&3dgp/notes/intersection.pdf
179// http://www.mrtc.mdh.se/projects/3Dgraphics/paperF.pdf
180bool BBOX_2D::Intersects( const SFVEC2F& aCenter, float aRadiusSquared ) const
181{
182 float fDistSq = 0.0f;
183
184 for( unsigned int i = 0; i < 2; i++ )
185 {
186 if( aCenter[i] < m_min[i] )
187 {
188 const float fDist = aCenter[i] - m_min[i];
189
190 fDistSq += fDist * fDist;
191 }
192 else
193 {
194 if( aCenter[i] > m_max[i] )
195 {
196 const float fDist = aCenter[i] - m_max[i];
197
198 fDistSq += fDist * fDist;
199 }
200 }
201 }
202
203 return ( fDistSq <= aRadiusSquared );
204}
205
206
207bool BBOX_2D::Intersects( const BBOX_2D& aBBox ) const
208{
209 wxASSERT( IsInitialized() );
210 wxASSERT( aBBox.IsInitialized() );
211
212 const bool x = ( m_max.x >= aBBox.m_min.x ) && ( m_min.x <= aBBox.m_max.x );
213 const bool y = ( m_max.y >= aBBox.m_min.y ) && ( m_min.y <= aBBox.m_max.y );
214
215 return ( x && y );
216}
217
218
219bool BBOX_2D::Inside( const SFVEC2F& aPoint ) const
220{
221 wxASSERT( IsInitialized() );
222
223 return ( ( aPoint.x >= m_min.x ) && ( aPoint.x <= m_max.x ) &&
224 ( aPoint.y >= m_min.y ) && ( aPoint.y <= m_max.y ) );
225}
226
227
228bool BBOX_2D::Inside( const BBOX_2D& aBBox ) const
229{
230 wxASSERT( IsInitialized() );
231 wxASSERT( aBBox.IsInitialized() );
232
233 return Inside( aBBox.Min() ) &&
234 Inside( aBBox.Max() );
235}
236
237
238float BBOX_2D::Area() const
239{
240 SFVEC2F extent = GetExtent();
241 return extent.x * extent.y;
242}
243
244
245// http://tavianator.com/fast-branchless-raybounding-box-intersections/
246bool BBOX_2D::Intersect( const RAY2D& aRay, float* t ) const
247{
248 wxASSERT( t );
249
250 const float tx1 = ( m_min.x - aRay.m_Origin.x ) * aRay.m_InvDir.x;
251 const float tx2 = ( m_max.x - aRay.m_Origin.x ) * aRay.m_InvDir.x;
252
253 float tmin = glm::min( tx1, tx2 );
254 float tmax = glm::max( tx1, tx2 );
255
256 const float ty1 = ( m_min.y - aRay.m_Origin.y ) * aRay.m_InvDir.y;
257 const float ty2 = ( m_max.y - aRay.m_Origin.y ) * aRay.m_InvDir.y;
258
259 tmin = glm::max( tmin, glm::min( ty1, ty2 ) );
260 tmax = glm::min( tmax, glm::max( ty1, ty2 ) );
261
262 if( tmin > 0.0f )
263 *t = tmin;
264 else
265 *t = tmax;
266
267 return ( tmax >= 0.0f ) && ( tmax >= tmin );
268}
269
270
271bool BBOX_2D::Intersect( const RAYSEG2D& aRaySeg ) const
272{
273 const float tx1 = ( m_min.x - aRaySeg.m_Start.x ) * aRaySeg.m_InvDir.x;
274 const float tx2 = ( m_max.x - aRaySeg.m_Start.x ) * aRaySeg.m_InvDir.x;
275
276 float tmin = glm::min( tx1, tx2 );
277 float tmax = glm::max( tx1, tx2 );
278
279 const float ty1 = ( m_min.y - aRaySeg.m_Start.y ) * aRaySeg.m_InvDir.y;
280 const float ty2 = ( m_max.y - aRaySeg.m_Start.y ) * aRaySeg.m_InvDir.y;
281
282 tmin = glm::max( tmin, glm::min( ty1, ty2 ) );
283 tmax = glm::min( tmax, glm::max( ty1, ty2 ) );
284
285 if( (tmax >= 0.0f) && (tmax >= tmin) )
286 {
287 const float t = (tmin > 0.0f)?tmin:tmax;
288
289 return ( t < aRaySeg.m_Length );
290 }
291
292 return false;
293}
294
295
296bool BBOX_2D::Intersect( const RAY2D& aRay, float* aOutHitT0, float* aOutHitT1 ) const
297{
298 wxASSERT( aOutHitT0 );
299 wxASSERT( aOutHitT1 );
300
301 const float tx1 = ( m_min.x - aRay.m_Origin.x ) * aRay.m_InvDir.x;
302 const float tx2 = ( m_max.x - aRay.m_Origin.x ) * aRay.m_InvDir.x;
303
304 float tmin = glm::min( tx1, tx2 );
305 float tmax = glm::max( tx1, tx2 );
306
307 const float ty1 = ( m_min.y - aRay.m_Origin.y ) * aRay.m_InvDir.y;
308 const float ty2 = ( m_max.y - aRay.m_Origin.y ) * aRay.m_InvDir.y;
309
310 tmin = glm::max( tmin, glm::min( ty1, ty2 ) );
311 tmax = glm::min( tmax, glm::max( ty1, ty2 ) );
312
313 *aOutHitT0 = ( tmin > 0.0f ) ? tmin : 0.0f;
314 *aOutHitT1 = tmax;
315
316 return ( tmax >= 0.0f ) && ( tmax >= tmin );
317}
Defines math related functions.
float NextFloatDown(float v)
float NextFloatUp(float v)
2D bounding box class definition.
float Perimeter() const
Definition bbox_2d.cpp:138
SFVEC2F GetCenter() const
Definition bbox_2d.cpp:115
bool Intersects(const BBOX_2D &aBBox) const
Test if a bounding box intersects this box.
Definition bbox_2d.cpp:207
~BBOX_2D()
Definition bbox_2d.cpp:52
unsigned int MaxDimension() const
Definition bbox_2d.cpp:127
SFVEC2F m_min
point of the lower position of the bounding box
Definition bbox_2d.h:201
void ScaleNextDown()
Scale a bounding box to the next float representation making it smaller.
Definition bbox_2d.cpp:168
SFVEC2F GetExtent() const
Definition bbox_2d.cpp:121
SFVEC2F m_max
point of the higher position of the bounding box
Definition bbox_2d.h:202
void Union(const SFVEC2F &aPoint)
Recalculate the bounding box adding a point.
Definition bbox_2d.cpp:89
void Scale(float aScale)
Scale a bounding box by its center.
Definition bbox_2d.cpp:146
bool IsInitialized() const
Check if this bounding box is already initialized.
Definition bbox_2d.cpp:75
const SFVEC2F & Min() const
Definition bbox_2d.h:171
float Area() const
Calculate the area of a bounding box.
Definition bbox_2d.cpp:238
bool Inside(const SFVEC2F &aPoint) const
Check is a point is inside this bounding box.
Definition bbox_2d.cpp:219
BBOX_2D()
Create with default values a bounding box (not initialized).
Definition bbox_2d.cpp:33
void Reset()
Reset the bounding box to zero and uninitialize it.
Definition bbox_2d.cpp:82
const SFVEC2F & Max() const
Definition bbox_2d.h:176
void Set(const SFVEC2F &aPbMin, const SFVEC2F &aPbMax)
Set bounding box with new parameters.
Definition bbox_2d.cpp:57
void ScaleNextUp()
Scale a bounding box to the next float representation making it larger.
Definition bbox_2d.cpp:158
bool Intersect(const RAY2D &aRay, float *t) const
Definition bbox_2d.cpp:246
Definition ray.h:90
SFVEC2F m_Origin
Definition ray.h:91
SFVEC2F m_InvDir
Definition ray.h:93
float m_Length
Definition ray.h:108
SFVEC2F m_InvDir
Definition ray.h:107
SFVEC2F m_Start
Definition ray.h:103
wxString result
Test unit parsing edge cases and error handling.
glm::vec2 SFVEC2F
Definition xv3d_types.h:38