KiCad PCB EDA Suite
croundsegment2d.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 <mrluzeiro@ua.pt>
5  * Copyright (C) 1992-2016 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, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
30 #include "croundsegment2d.h"
31 #include <wx/debug.h>
32 
33 
35  const SFVEC2F& aStart, const SFVEC2F& aEnd, float aWidth, const BOARD_ITEM& aBoardItem )
36  : COBJECT2D( OBJECT2D_TYPE::ROUNDSEG, aBoardItem ), m_segment( aStart, aEnd )
37 {
38  wxASSERT( aStart != aEnd );
39 
40  m_radius = (aWidth / 2.0f);
42  m_width = aWidth;
43 
44  SFVEC2F leftRadiusOffset( -m_segment.m_Dir.y * m_radius,
45  m_segment.m_Dir.x * m_radius );
46 
47  m_leftStart = aStart + leftRadiusOffset;
48  m_leftEnd = aEnd + leftRadiusOffset;
50  m_leftDir = glm::normalize( m_leftEndMinusStart );
51 
52  SFVEC2F rightRadiusOffset( -leftRadiusOffset.x,
53  -leftRadiusOffset.y );
54  m_rightStart = aEnd + rightRadiusOffset;
55  m_rightEnd = aStart + rightRadiusOffset;
57  m_rightDir = glm::normalize( m_rightEndMinusStart );
58 
59  m_bbox.Reset();
60  m_bbox.Set( aStart, aEnd );
65 
66  wxASSERT( m_bbox.IsInitialized() );
67 }
68 
69 
70 bool CROUNDSEGMENT2D::Intersects( const CBBOX2D &aBBox ) const
71 {
72  if( !m_bbox.Intersects( aBBox ) )
73  return false;
74 
75  if( (aBBox.Max().x > m_bbox.Max().x) &&
76  (aBBox.Max().y > m_bbox.Max().y) &&
77  (aBBox.Min().x < m_bbox.Min().x) &&
78  (aBBox.Min().y < m_bbox.Min().y)
79  )
80  return true;
81 
82  SFVEC2F v[4];
83 
84  v[0] = aBBox.Min();
85  v[1] = SFVEC2F( aBBox.Min().x, aBBox.Max().y );
86  v[2] = aBBox.Max();
87  v[3] = SFVEC2F( aBBox.Max().x, aBBox.Min().y );
88 
89  // Test against the main rectangle segment
90  if( IntersectSegment( m_leftStart, m_leftEndMinusStart, v[0], v[1] - v[0] ) )
91  return true;
92 
93  if( IntersectSegment( m_leftStart, m_leftEndMinusStart, v[1], v[2] - v[1] ) )
94  return true;
95 
96  if( IntersectSegment( m_leftStart, m_leftEndMinusStart, v[2], v[3] - v[2] ) )
97  return true;
98 
99  if( IntersectSegment( m_leftStart, m_leftEndMinusStart, v[3], v[0] - v[3] ) )
100  return true;
101 
102 
103  if( IntersectSegment( m_rightStart, m_rightEndMinusStart, v[0], v[1] - v[0] ) )
104  return true;
105 
106  if( IntersectSegment( m_rightStart, m_rightEndMinusStart, v[1], v[2] - v[1] ) )
107  return true;
108 
109  if( IntersectSegment( m_rightStart, m_rightEndMinusStart, v[2], v[3] - v[2] ) )
110  return true;
111 
112  if( IntersectSegment( m_rightStart, m_rightEndMinusStart, v[3], v[0] - v[3] ) )
113  return true;
114 
115  // Test the two circles
117  return true;
118 
120  return true;
121 
122  return false;
123 }
124 
125 
126 bool CROUNDSEGMENT2D::Overlaps( const CBBOX2D &aBBox ) const
127 {
128  // NOT IMPLEMENTED
129  return false;
130 }
131 
132 
134  float *aOutT,
135  SFVEC2F *aNormalOut ) const
136 {
137  wxASSERT( aOutT );
138  wxASSERT( aNormalOut );
139 
140  const bool start_is_inside = IsPointInside( aSegRay.m_Start );
141  const bool end_is_inside = IsPointInside( aSegRay.m_End );
142 
143  // If segment if inside there are no hits
144  if( start_is_inside && end_is_inside )
145  return false;
146 
147  bool hitted = false;
148 
149  float closerHitT = FLT_MAX;
150  float farHitT = FLT_MAX;
151 
152  SFVEC2F closerHitNormal;
153  SFVEC2F farHitNormal;
154 
155  float leftSegT;
156  const bool leftSegmentHit = aSegRay.IntersectSegment( m_leftStart,
158  &leftSegT );
159 
160  if( leftSegmentHit )
161  {
162  hitted = true;
163  closerHitT = leftSegT;
164  farHitT = leftSegT;
165 
166  closerHitNormal = SFVEC2F( -m_leftDir.y, m_leftDir.x );
167  farHitNormal = SFVEC2F( -m_leftDir.y, m_leftDir.x );
168  }
169 
170  float rightSegT;
171  const bool rightSegmentHit = aSegRay.IntersectSegment( m_rightStart,
173  &rightSegT );
174 
175  if( rightSegmentHit )
176  {
177  if( !start_is_inside )
178  if( (hitted == false) || (rightSegT < closerHitT) )
179  {
180  closerHitT = rightSegT;
181  closerHitNormal = SFVEC2F( -m_rightDir.y, m_rightDir.x );
182  }
183 
184  if( start_is_inside )
185  if( (hitted == false) || (rightSegT > farHitT) )
186  {
187  farHitT = rightSegT;
188  farHitNormal = SFVEC2F( -m_rightDir.y, m_rightDir.x );
189  }
190 
191  hitted = true;
192  }
193 
194  float circleStart_T0;
195  float circleStart_T1;
196  SFVEC2F circleStart_N0;
197  SFVEC2F circleStart_N1;
198 
199  const bool startCircleHit = aSegRay.IntersectCircle( m_segment.m_Start, m_radius,
200  &circleStart_T0, &circleStart_T1,
201  &circleStart_N0, &circleStart_N1 );
202 
203  if( startCircleHit )
204  {
205  if( circleStart_T0 > 0.0f )
206  {
207  if( !start_is_inside )
208  if( (hitted == false) || (circleStart_T0 < closerHitT) )
209  {
210  closerHitT = circleStart_T0;
211  closerHitNormal = circleStart_N0;
212  }
213 
214  if( start_is_inside )
215  if( (hitted == false) || (circleStart_T1 > farHitT) )
216  {
217  farHitT = circleStart_T1;
218  farHitNormal = circleStart_N1;
219  }
220  }
221  else
222  {
223  // This can only happen if the ray starts inside
224  if( (hitted == false) || (circleStart_T1 > farHitT) )
225  {
226  farHitT = circleStart_T1;
227  farHitNormal = circleStart_N1;
228  }
229  }
230 
231  hitted = true;
232  }
233 
234  float circleEnd_T0;
235  float circleEnd_T1;
236  SFVEC2F circleEnd_N0;
237  SFVEC2F circleEnd_N1;
238 
239  const bool rightCircleHit = aSegRay.IntersectCircle( m_segment.m_End, m_radius,
240  &circleEnd_T0, &circleEnd_T1,
241  &circleEnd_N0, &circleEnd_N1 );
242  if( rightCircleHit )
243  {
244  if( circleEnd_T0 > 0.0f )
245  {
246  if( !start_is_inside )
247  if( (hitted == false) || (circleEnd_T0 < closerHitT) )
248  {
249  closerHitT = circleEnd_T0;
250  closerHitNormal = circleEnd_N0;
251  }
252 
253  if( start_is_inside )
254  if( (hitted == false) || (circleEnd_T1 > farHitT) )
255  {
256  farHitT = circleEnd_T1;
257  farHitNormal = circleEnd_N1;
258  }
259  }
260  else
261  {
262  // This can only happen if the ray starts inside
263  if( (hitted == false) || (circleEnd_T1 > farHitT) )
264  {
265  farHitT = circleEnd_T1;
266  farHitNormal = circleEnd_N1;
267  }
268  }
269 
270  hitted = true;
271  }
272 
273  if( hitted )
274  {
275  if( !start_is_inside )
276  {
277  *aOutT = closerHitT;
278  //wxASSERT( (closerHitT > 0.0f) && (closerHitT <= 1.0f) );
279  *aNormalOut = closerHitNormal;
280  }
281  else
282  {
283  wxASSERT( (farHitT >= 0.0f) && (farHitT <= 1.0f) );
284 
285  *aOutT = farHitT;
286  *aNormalOut = -farHitNormal; // the normal started inside, so invert it
287  }
288  }
289 
290  return hitted;
291 }
292 
293 
295 {
296  if( !m_bbox.Intersects( aBBox ) )
298 
299  SFVEC2F v[4];
300 
301  v[0] = aBBox.Min();
302  v[1] = aBBox.Max();
303  v[2] = SFVEC2F( aBBox.Min().x, aBBox.Max().y );
304  v[3] = SFVEC2F( aBBox.Max().x, aBBox.Min().y );
305 
306  bool isInside[4];
307 
308  isInside[0] = IsPointInside( v[0] );
309  isInside[1] = IsPointInside( v[1] );
310  isInside[2] = IsPointInside( v[2] );
311  isInside[3] = IsPointInside( v[3] );
312 
313  // Check if all points are inside the circle
314  if( isInside[0] &&
315  isInside[1] &&
316  isInside[2] &&
317  isInside[3] )
319 
320  // Check if any point is inside the circle
321  if( isInside[0] ||
322  isInside[1] ||
323  isInside[2] ||
324  isInside[3] )
326 
328 }
329 
330 
331 bool CROUNDSEGMENT2D::IsPointInside( const SFVEC2F &aPoint ) const
332 {
333  float dSquared = m_segment.DistanceToPointSquared( aPoint );
334 
335  if( dSquared <= m_radius_squared )
336  return true;
337 
338  return false;
339 }
SFVEC2F m_rightEndMinusStart
INTERSECTION_RESULT
Definition: cobject2d.h:38
bool Intersect(const RAYSEG2D &aSegRay, float *aOutT, SFVEC2F *aNormalOut) const override
Function Intersect.
bool Intersects(const CBBOX2D &aBBox) const override
Function Intersects.
BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class,...
const SFVEC2F & Min() const
Function Min return the minimun vertex pointer.
Definition: cbbox2d.h:176
CBBOX manages a bounding box defined by two SFVEC2F min max points.
Definition: cbbox2d.h:40
bool IntersectCircle(const SFVEC2F &aCenter, float aRadius, float *aOutT0, float *aOutT1, SFVEC2F *aOutNormalT0, SFVEC2F *aOutNormalT1) const
Definition: ray.cpp:348
SFVEC2F m_Dir
Definition: ray.h:115
void Reset()
Function Reset reset the bounding box to zero and de-initialized it.
Definition: cbbox2d.cpp:88
bool Overlaps(const CBBOX2D &aBBox) const override
Function Overlaps.
glm::vec2 SFVEC2F
Definition: xv3d_types.h:45
bool IntersectSegment(const SFVEC2F &aStart, const SFVEC2F &aEnd_minus_start, float *aOutT) const
Definition: ray.cpp:291
bool Intersects(const CBBOX2D &aBBox) const
Function Intersects test if a bounding box intersects this box.
Definition: cbbox2d.cpp:213
void Set(const SFVEC2F &aPbMin, const SFVEC2F &aPbMax)
Function Set Set bounding box with new parameters.
Definition: cbbox2d.cpp:61
bool IsInitialized() const
Function IsInitialized check if this bounding box is already initialized.
Definition: cbbox2d.cpp:79
SFVEC2F m_End
Definition: ray.h:113
CROUNDSEGMENT2D(const SFVEC2F &aStart, const SFVEC2F &aEnd, float aWidth, const BOARD_ITEM &aBoardItem)
const SFVEC2F & Max() const
Function Max return the maximum vertex pointer.
Definition: cbbox2d.h:183
SFVEC2F m_leftEndMinusStart
bool IntersectSegment(const SFVEC2F &aStartA, const SFVEC2F &aEnd_minus_startA, const SFVEC2F &aStartB, const SFVEC2F &aEnd_minus_startB)
Definition: ray.cpp:183
void ScaleNextUp()
Function ScaleNextUp scales a bounding box to the next float representation making it larger.
Definition: cbbox2d.cpp:164
CBBOX2D m_bbox
Definition: cobject2d.h:65
SFVEC2F m_Start
Definition: ray.h:112
INTERSECTION_RESULT IsBBoxInside(const CBBOX2D &aBBox) const override
Function IsBBoxInside.
float DistanceToPointSquared(const SFVEC2F &aPoint) const
Definition: ray.cpp:325
SFVEC2F m_centroid
Definition: cobject2d.h:66
OBJECT2D_TYPE
Definition: cobject2d.h:46
SFVEC2F GetCenter() const
Function GetCenter return the center point of the bounding box.
Definition: cbbox2d.cpp:121
bool IsPointInside(const SFVEC2F &aPoint) const override
Definition: ray.h:110