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