KiCad PCB EDA Suite
Loading...
Searching...
No Matches
frustum_3d.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 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
27
28#include "3d_fastmath.h"
29#include "frustum_3d.h"
30#include <cmath>
31
32
33TRUNCATED_CONE::TRUNCATED_CONE( SFVEC2F aCenterPoint, float aZmin, float aZmax, float aRadiusMin,
34 float aRadiusMax )
35 : OBJECT_3D( OBJECT_3D_TYPE::CYLINDER ) // Reuse CYLINDER type for now
36{
37 m_center = aCenterPoint;
38 m_zMin = aZmin;
39 m_zMax = aZmax;
40 m_radiusMin = aRadiusMin;
41 m_radiusMax = aRadiusMax;
42 m_height = aZmax - aZmin;
43 m_slope = ( m_height > 0.0f ) ? ( aRadiusMax - aRadiusMin ) / m_height : 0.0f;
44
45 // Bounding box uses the larger radius
46 const float maxRadius = std::max( aRadiusMin, aRadiusMax );
47 m_bbox.Set( SFVEC3F( aCenterPoint.x - maxRadius, aCenterPoint.y - maxRadius, aZmin ),
48 SFVEC3F( aCenterPoint.x + maxRadius, aCenterPoint.y + maxRadius, aZmax ) );
49 m_bbox.ScaleNextUp();
50 m_centroid = m_bbox.GetCenter();
51}
52
53
54bool TRUNCATED_CONE::Intersect( const RAY& aRay, HITINFO& aHitInfo ) const
55{
56 // Ray-cone intersection for a vertical cone with apex on the Z axis.
57 // The cone surface is defined by: (x-cx)^2 + (y-cy)^2 = r(z)^2
58 // where r(z) = radiusMin + slope * (z - zMin)
59 //
60 // Substituting the ray equation P = O + t*D:
61 // (Ox + t*Dx - cx)^2 + (Oy + t*Dy - cy)^2 = (radiusMin + slope*(Oz + t*Dz - zMin))^2
62
63 const double OCx = aRay.m_Origin.x - m_center.x;
64 const double OCy = aRay.m_Origin.y - m_center.y;
65 const double OCz = aRay.m_Origin.z - m_zMin; // Z relative to cone base
66
67 const double Dx = aRay.m_Dir.x;
68 const double Dy = aRay.m_Dir.y;
69 const double Dz = aRay.m_Dir.z;
70
71 const double r0 = m_radiusMin;
72 const double k = m_slope; // dr/dz
73
74 // Expanding the equation gives us a quadratic: a*t^2 + 2*b*t + c = 0
75 // Note: we use 2*b to simplify the quadratic formula
76 const double a = Dx * Dx + Dy * Dy - k * k * Dz * Dz;
77 const double b = OCx * Dx + OCy * Dy - k * ( r0 + k * OCz ) * Dz;
78 const double c = OCx * OCx + OCy * OCy - ( r0 + k * OCz ) * ( r0 + k * OCz );
79
80 const double discriminant = b * b - a * c;
81
82 if( discriminant < 0.0 )
83 return false;
84
85 bool hitResult = false;
86 float tHit = aHitInfo.m_tHit;
87 SFVEC3F hitNormal;
88
89 const double sqrtDisc = std::sqrt( discriminant );
90
91 // Check both roots
92 for( int i = 0; i < 2; ++i )
93 {
94 double t;
95 if( std::abs( a ) < 1e-10 )
96 {
97 // Nearly linear case
98 if( std::abs( b ) < 1e-10 )
99 continue;
100 t = -c / ( 2.0 * b );
101 if( i == 1 )
102 continue; // Only one solution in linear case
103 }
104 else
105 {
106 t = ( -b + ( i == 0 ? -sqrtDisc : sqrtDisc ) ) / a;
107 }
108
109 if( t <= 0.0f || t >= tHit )
110 continue;
111
112 const float z = aRay.m_Origin.z + t * aRay.m_Dir.z;
113
114 if( z < m_zMin || z > m_zMax )
115 continue;
116
117 // Valid hit on cone surface
118 tHit = t;
119 hitResult = true;
120
121 const SFVEC3F hitPoint = aRay.at( t );
122 const float hitRadius = m_radiusMin + m_slope * ( z - m_zMin );
123
124 if( hitRadius > 1e-6f )
125 {
126 // Normal points outward from cone surface
127 // For a cone, the normal has both radial and vertical components
128 const float invR = 1.0f / hitRadius;
129 const float nx = -( hitPoint.x - m_center.x ) * invR;
130 const float ny = -( hitPoint.y - m_center.y ) * invR;
131 // The vertical component depends on the slope
132 const float nz = m_slope / std::sqrt( 1.0f + m_slope * m_slope );
133
134 hitNormal = glm::normalize( SFVEC3F( nx, ny, nz ) );
135 }
136 else
137 {
138 hitNormal = SFVEC3F( 0.0f, 0.0f, -1.0f );
139 }
140
141 break; // Take the first valid hit (closer one)
142 }
143
144 if( hitResult )
145 {
146 aHitInfo.m_tHit = tHit;
147 aHitInfo.m_HitPoint = aRay.at( tHit );
148 aHitInfo.m_HitNormal = hitNormal;
149
150 m_material->Generate( aHitInfo.m_HitNormal, aRay, aHitInfo );
151
152 aHitInfo.pHitObject = this;
153 }
154
155 return hitResult;
156}
157
158
159bool TRUNCATED_CONE::IntersectP( const RAY& aRay, float aMaxDistance ) const
160{
161 const double OCx = aRay.m_Origin.x - m_center.x;
162 const double OCy = aRay.m_Origin.y - m_center.y;
163 const double OCz = aRay.m_Origin.z - m_zMin;
164
165 const double Dx = aRay.m_Dir.x;
166 const double Dy = aRay.m_Dir.y;
167 const double Dz = aRay.m_Dir.z;
168
169 const double r0 = m_radiusMin;
170 const double k = m_slope;
171
172 const double a = Dx * Dx + Dy * Dy - k * k * Dz * Dz;
173 const double b = OCx * Dx + OCy * Dy - k * ( r0 + k * OCz ) * Dz;
174 const double c = OCx * OCx + OCy * OCy - ( r0 + k * OCz ) * ( r0 + k * OCz );
175
176 const double discriminant = b * b - a * c;
177
178 if( discriminant < 0.0 )
179 return false;
180
181 const double sqrtDisc = std::sqrt( discriminant );
182
183 for( int i = 0; i < 2; ++i )
184 {
185 double t;
186 if( std::abs( a ) < 1e-10 )
187 {
188 if( std::abs( b ) < 1e-10 )
189 continue;
190 t = -c / ( 2.0 * b );
191 if( i == 1 )
192 continue;
193 }
194 else
195 {
196 t = ( -b + ( i == 0 ? -sqrtDisc : sqrtDisc ) ) / a;
197 }
198
199 if( t <= 0.0f || t >= aMaxDistance )
200 continue;
201
202 const float z = aRay.m_Origin.z + t * aRay.m_Dir.z;
203
204 if( z >= m_zMin && z <= m_zMax )
205 return true;
206 }
207
208 return false;
209}
210
211
212bool TRUNCATED_CONE::Intersects( const BBOX_3D& aBBox ) const
213{
214 // Simple bounding box check
215 return m_bbox.Intersects( aBBox );
216}
217
218
219SFVEC3F TRUNCATED_CONE::GetDiffuseColor( const HITINFO& /* aHitInfo */ ) const
220{
221 return m_diffusecolor;
222}
Defines math related functions.
A vertical cylinder.
Definition cylinder_3d.h:34
BBOX_3D m_bbox
Definition object_3d.h:93
SFVEC3F m_centroid
Definition object_3d.h:94
OBJECT_3D(OBJECT_3D_TYPE aObjType)
Definition object_3d.cpp:36
const MATERIAL * m_material
Definition object_3d.h:96
bool Intersect(const RAY &aRay, HITINFO &aHitInfo) const override
bool IntersectP(const RAY &aRay, float aMaxDistance) const override
float m_radiusMax
Definition frustum_3d.h:57
SFVEC3F m_diffusecolor
Definition frustum_3d.h:62
SFVEC2F m_center
Definition frustum_3d.h:55
bool Intersects(const BBOX_3D &aBBox) const override
SFVEC3F GetDiffuseColor(const HITINFO &aHitInfo) const override
TRUNCATED_CONE(SFVEC2F aCenterPoint, float aZmin, float aZmax, float aRadiusMin, float aRadiusMax)
float m_radiusMin
Definition frustum_3d.h:56
A truncated cone for raytracing, used for countersink visualization.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:400
OBJECT_3D_TYPE
Definition object_3d.h:35
Manage a bounding box defined by two SFVEC3F min max points.
Definition bbox_3d.h:39
Stores the hit information of a ray with a point on the surface of a object.
Definition hitinfo.h:32
float m_tHit
( 4) distance
Definition hitinfo.h:34
const OBJECT_3D * pHitObject
( 4) Object that was hitted
Definition hitinfo.h:36
SFVEC3F m_HitNormal
(12) normal at the hit point
Definition hitinfo.h:33
SFVEC3F m_HitPoint
(12) hit position
Definition hitinfo.h:40
Definition ray.h:59
SFVEC3F m_Dir
Definition ray.h:63
SFVEC3F m_Origin
Definition ray.h:60
SFVEC3F at(float t) const
Definition ray.h:80
glm::vec2 SFVEC2F
Definition xv3d_types.h:38
glm::vec3 SFVEC3F
Definition xv3d_types.h:40