/* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2015-2016 Mario Luzeiro * Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, you may find one here: * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * or you may search the http://www.gnu.org website for the version 2 license, * or you may write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ /** * @file ccylinder.cpp * @brief */ #include "3d_fastmath.h" #include "ccylinder.h" CVCYLINDER::CVCYLINDER( SFVEC2F aCenterPoint, float aZmin, float aZmax, float aRadius ) : COBJECT( OBJ3D_CYLINDER ) { m_center = aCenterPoint; m_radius_squared = aRadius * aRadius; m_inv_radius = 1.0f / aRadius; m_bbox.Set( SFVEC3F( aCenterPoint.x - aRadius, aCenterPoint.y - aRadius, aZmin ), SFVEC3F( aCenterPoint.x + aRadius, aCenterPoint.y + aRadius, aZmax ) ); m_bbox.ScaleNextUp(); m_centroid = m_bbox.GetCenter(); } bool CVCYLINDER::Intersect( const RAY &aRay, HITINFO &aHitInfo ) const { // Based on: // http://www.cs.utah.edu/~lha/Code%206620%20/Ray4/Cylinder.cpp // Ray-sphere intersection: geometric // ///////////////////////////////////////////////////////////////////////// const double OCx_Start = aRay.m_Origin.x - m_center.x; const double OCy_Start = aRay.m_Origin.y - m_center.y; const double p_dot_p = OCx_Start * OCx_Start + OCy_Start * OCy_Start; const double a = (double)aRay.m_Dir.x * (double)aRay.m_Dir.x + (double)aRay.m_Dir.y * (double)aRay.m_Dir.y; const double b = (double)aRay.m_Dir.x * (double)OCx_Start + (double)aRay.m_Dir.y * (double)OCy_Start; const double c = p_dot_p - m_radius_squared; const float delta = (float)(b * b - a * c); bool hitResult = false; if( delta > FLT_EPSILON ) { const float inv_a = 1.0 / a; const float sdelta = sqrtf( delta ); const float t = (-b - sdelta) * inv_a; const float z = aRay.m_Origin.z + t * aRay.m_Dir.z; if( (z >= m_bbox.Min().z) && (z <= m_bbox.Max().z) ) { if( t < aHitInfo.m_tHit ) { hitResult = true; aHitInfo.m_tHit = t; } } if( !hitResult ) { const float t1 = (-b + sdelta) * inv_a; const float z1 = aRay.m_Origin.z + t1 * aRay.m_Dir.z; if( (z1 > m_bbox.Min().z ) && (z1 < m_bbox.Max().z ) ) { if( t1 < aHitInfo.m_tHit ) { hitResult = true; aHitInfo.m_tHit = t1; } } } } if( hitResult ) { aHitInfo.m_HitPoint = aRay.at( aHitInfo.m_tHit ); const SFVEC2F hitPoint2D = SFVEC2F( aHitInfo.m_HitPoint.x, aHitInfo.m_HitPoint.y ); aHitInfo.m_HitNormal = SFVEC3F( -(hitPoint2D.x - m_center.x) * m_inv_radius, -(hitPoint2D.y - m_center.y) * m_inv_radius, 0.0f ); m_material->PerturbeNormal( aHitInfo.m_HitNormal, aRay, aHitInfo ); aHitInfo.pHitObject = this; } return hitResult; } bool CVCYLINDER::IntersectP(const RAY &aRay , float aMaxDistance ) const { // Based on: // http://www.cs.utah.edu/~lha/Code%206620%20/Ray4/Cylinder.cpp // Ray-sphere intersection: geometric // ///////////////////////////////////////////////////////////////////////// const double OCx_Start = aRay.m_Origin.x - m_center.x; const double OCy_Start = aRay.m_Origin.y - m_center.y; const double p_dot_p = OCx_Start * OCx_Start + OCy_Start * OCy_Start; const double a = (double)aRay.m_Dir.x * (double)aRay.m_Dir.x + (double)aRay.m_Dir.y * (double)aRay.m_Dir.y; const double b = (double)aRay.m_Dir.x * (double)OCx_Start + (double)aRay.m_Dir.y * (double)OCy_Start; const double c = p_dot_p - m_radius_squared; const float delta = (float)(b * b - a * c); if( delta > FLT_EPSILON ) { const float inv_a = 1.0 / a; const float sdelta = sqrtf( delta ); const float t = (-b - sdelta) * inv_a; const float z = aRay.m_Origin.z + t * aRay.m_Dir.z; if( (z >= m_bbox.Min().z) && (z <= m_bbox.Max().z) ) { if( t < aMaxDistance ) return true; } const float t1 = (-b + sdelta) * inv_a; const float z1 = aRay.m_Origin.z + t1 * aRay.m_Dir.z; if( (z1 > m_bbox.Min().z ) && (z1 < m_bbox.Max().z ) ) { if( t1 < aMaxDistance ) return true; } } return false; } bool CVCYLINDER::Intersects( const CBBOX &aBBox ) const { // !TODO: improove return m_bbox.Intersects( aBBox ); } SFVEC3F CVCYLINDER::GetDiffuseColor( const HITINFO &aHitInfo ) const { (void)aHitInfo; // unused return m_diffusecolor; }