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