Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-09 07:48:54

0001 #pragma once
0002 /**
0003 intersect_leaf_oldcylinder
0004 ------------------------
0005 
0006 For ascii art explanation of the maths see optixrap/cu/intersect_ztubs.h
0007 
0008 * handling inner radius within the primitive would be useful, but need to simplify first 
0009 * ideas to simplify
0010 
0011   * adopt natural cylinder frame, require abs(z1) = abs(z2) ie -z:z 
0012   * split into separate methods for infinite intersect 
0013 
0014 
0015 **/
0016 
0017 #define CSG_OLDCYLINDER_PRECISION_ISSUE 1 
0018 
0019 LEAF_FUNC
0020 void intersect_leaf_oldcylinder( bool& valid_isect, float4& isect, const quad& q0, const quad& q1, const float t_min, const float3& ray_origin, const float3& ray_direction )
0021 {
0022     const float   radius = q0.f.w ; 
0023     const float       z1 = q1.f.x  ; 
0024     const float       z2 = q1.f.y  ; 
0025 
0026     const float  sizeZ = z2 - z1 ; 
0027     const float3 position = make_float3( q0.f.x, q0.f.y, z1 ); // P: point on axis at base of cylinder
0028 
0029 #ifdef DEBUG_RECORD
0030     printf("//[intersect_leaf_cylinder radius %10.4f z1 %10.4f z2 %10.4f sizeZ %10.4f \n", radius, z1, z2, sizeZ ); 
0031 #endif
0032     const float3 m = ray_origin - position ;          // m: ray origin in cylinder frame (cylinder origin at base point P)
0033     const float3 n = ray_direction ;                  // n: ray direction vector (not normalized)
0034     const float3 d = make_float3(0.f, 0.f, sizeZ );   // d: (PQ) cylinder axis vector (not normalized)
0035 
0036     float rr = radius*radius ; 
0037     float3 dnorm = normalize(d);  
0038 
0039     float mm = dot(m, m) ;   //    
0040     float nn = dot(n, n) ;   // all 1. when ray_direction normalized
0041     float dd = dot(d, d) ;   // sizeZ*sizeZ 
0042     float nd = dot(n, d) ;   // dot product of axis vector and ray, ie -0.3/0.3 (for hz 0.15 cyl)
0043     float md = dot(m, d) ;
0044     float mn = dot(m, n) ; 
0045     float k = mm - rr ; 
0046 
0047     // quadratic coefficients of t,     a tt + 2b t + c = 0 
0048     // see bk-;bk-rtcdcy for derivation of these coefficients
0049 
0050     float a = dd*nn - nd*nd ;   
0051     float b = dd*mn - nd*md ;
0052     float c = dd*k - md*md ; 
0053 
0054 
0055     float disc = b*b-a*c;
0056     float t_cand = t_min ; 
0057 
0058 
0059     enum {  ENDCAP_P=1,  ENDCAP_Q=2 } ; 
0060 
0061     // axial ray endcap handling : can treat axial rays in 2d way 
0062     if(fabs(a) < 1e-6f)     
0063     {
0064 
0065 #ifdef DEBUG_RECORD
0066     printf("//intersect_leaf_cylinder : axial ray endcap handling, a %10.4g c(dd*k - md*md) %10.4g dd %10.4g k %10.4g md %10.4g  \n", a, c,dd,k,md ); 
0067 #endif
0068         if(c > 0.f)
0069         {
0070             valid_isect = false ; 
0071             return ;  // ray starts and ends outside cylinder
0072         }
0073 
0074 #ifdef CSG_OLDCYLINDER_PRECISION_ISSUE
0075         float t_PCAP_AX = -mn/nn  ;      
0076         float t_QCAP_AX = (nd - mn)/nn ;  
0077     
0078         if(md < 0.f )     // ray origin on P side  
0079         {
0080             t_cand = t_PCAP_AX > t_min ? t_PCAP_AX : t_QCAP_AX ;
0081         } 
0082         else if(md > dd )  // ray origin on Q side 
0083         {
0084             t_cand = t_QCAP_AX > t_min ? t_QCAP_AX : t_PCAP_AX ;
0085         }
0086         else              // ray origin inside,   nd > 0 ray along +d towards Q  
0087         {
0088             t_cand = nd > 0.f ? t_QCAP_AX : t_PCAP_AX ;  
0089         }
0090 
0091 
0092 #else
0093         float t_PCAP_AX = copysignf(1.f, ray_direction.z)*(z1 - ray_origin.z) ;  // up/down oriented to match the dot product approach but more simply
0094         float t_QCAP_AX = copysignf(1.f, ray_direction.z)*(z2 - ray_origin.z) ;  // up/down oriented to match the dot product approach but more simply
0095 
0096         if(ray_origin.z < z1)
0097         {
0098             t_cand = t_PCAP_AX > t_min ? t_PCAP_AX : t_QCAP_AX ;
0099         }
0100         else if( ray_origin.z > z2 )
0101         {
0102             t_cand = t_QCAP_AX > t_min ? t_QCAP_AX : t_PCAP_AX ;
0103         }
0104         else              // ray origin inside,   nd > 0 ray along +d towards Q  
0105         {
0106             t_cand = ray_direction.z > 0.f ? t_QCAP_AX : t_PCAP_AX ;  
0107         }
0108 #endif
0109 
0110         unsigned endcap = t_cand == t_PCAP_AX ? ENDCAP_P : ( t_cand == t_QCAP_AX ? ENDCAP_Q : 0u ) ;
0111 
0112         bool has_axial_intersect = t_cand > t_min && endcap > 0u ;
0113 
0114         if(has_axial_intersect)
0115         {
0116             float sign = endcap == ENDCAP_P ? -1.f : 1.f ;  
0117             isect.x = sign*dnorm.x ; 
0118             isect.y = sign*dnorm.y ; 
0119             isect.z = sign*dnorm.z ; 
0120             isect.w = t_cand ;      
0121 
0122 #ifdef DEBUG_CYLINDER
0123             CSGDebug_Cylinder dbg = {} ; 
0124 
0125             dbg.ray_origin = ray_origin ;   // 0
0126             dbg.rr = rr ; 
0127 
0128             dbg.ray_direction = ray_direction ;  // 1 
0129             dbg.k  = k ; 
0130 
0131             dbg.m = m ;     // 2
0132             dbg.mm = mm ;  
0133 
0134             dbg.n = n ;     // 3
0135             dbg.nn = nn ;  
0136 
0137             dbg.d = d ;     // 4
0138             dbg.dd = dd ;  
0139 
0140             dbg.nd = nd ;   // 5 
0141             dbg.md = md ; 
0142             dbg.mn = mn ; 
0143             dbg.checkz = ray_origin.z+ray_direction.z*t_cand ;
0144 
0145             dbg.a = a ;    // 6 
0146             dbg.b = b ; 
0147             dbg.c = c ; 
0148             dbg.disc = disc ; 
0149 
0150             dbg.isect = isect ;      // 7 
0151 
0152             CSGDebug_Cylinder::record.push_back(dbg); 
0153 #endif
0154         }
0155         valid_isect = has_axial_intersect ; 
0156         return ; 
0157     }   // end-of-axial-ray endcap handling 
0158     
0159 
0160 
0161     if(disc > 0.0f)  // has intersections with the infinite cylinder
0162     {
0163         float t_NEAR, t_FAR, sdisc ;   
0164         robust_quadratic_roots(t_NEAR, t_FAR, disc, sdisc, a, b, c); //  Solving:  a t^2 + 2 b t +  c = 0 
0165 
0166 #ifdef DEBUG_CYLINDER
0167         /*
0168         // see CSG/sympy_cylinder.py 
0169         const float& ox = ray_origin.x ; 
0170         const float& oy = ray_origin.y ; 
0171         const float& vx = ray_direction.x ; 
0172         const float& vy = ray_direction.y ; 
0173 
0174         float a1 = vx*vx + vy*vy ; 
0175         float b1 = ox*vx + oy*vy ; 
0176         float c1 = ox*ox + oy*oy - rr ; 
0177 
0178         float disc1 = b1*b1-a1*c1;
0179         
0180         //printf("// intersect_leaf_cylinder  a %10.4f a1 %10.4f a/a1 %10.4f  b %10.4f b1 %10.4f b/b1 %10.4f     c %10.4f c1 %10.4f c/c1 %10.4f  \n", 
0181         //    a, a1, a/a1, 
0182         //    b, b1, b/b1, 
0183         //    c, c1, c/c1 ); 
0184    
0185 
0186         float t_NEAR1, t_FAR1, sdisc1 ;   
0187         robust_quadratic_roots(t_NEAR1, t_FAR1, disc1, sdisc1, a1, b1, c1); //  Solving:  a t^2 + 2 b t +  c = 0 
0188 
0189         printf("// intersect_leaf_cylinder  t_NEAR %10.4f t_NEAR1 %10.4f t_FAR %10.4f t_FAR1 %10.4f \n", t_NEAR, t_NEAR1, t_FAR, t_FAR1 );  
0190 
0191         */
0192 #endif
0193 
0194 
0195         float t_PCAP = -md/nd ; 
0196         float t_QCAP = (dd-md)/nd ;   
0197 
0198 
0199         float aNEAR = md + t_NEAR*nd ;        // axial coord of near intersection point * sizeZ
0200         float aFAR  = md + t_FAR*nd ;         // axial coord of far intersection point  * sizeZ
0201 
0202         float3 P1 = ray_origin + t_NEAR*ray_direction ;  
0203         float3 P2 = ray_origin + t_FAR*ray_direction ;  
0204 
0205         float3 N1  = (P1 - position)/radius  ;     // HMM: subtracting fixed position at base ?
0206         float3 N2  = (P2 - position)/radius  ;     // that is wrong for the z component, but z component is zero so no problem 
0207 
0208         float checkr = 0.f ; 
0209         float checkr_PCAP = k + t_PCAP*(2.f*mn + t_PCAP*nn) ; // bracket typo in RTCD book, 2*t*t makes no sense   
0210         float checkr_QCAP = k + dd - 2.0f*md + t_QCAP*(2.f*(mn-nd)+t_QCAP*nn) ;             
0211 
0212 
0213         if( aNEAR > 0.f && aNEAR < dd )  // near intersection inside cylinder z range
0214         {
0215             t_cand = t_NEAR ; 
0216             checkr = -1.f ; 
0217         } 
0218         else if( aNEAR < 0.f ) //  near intersection outside cylinder z range, on P side
0219         {
0220             t_cand =  nd > 0.f ? t_PCAP : t_min ;   // nd > 0, ray headed upwards (+z)
0221             checkr = checkr_PCAP ; 
0222         } 
0223         else if( aNEAR > dd ) //  intersection outside cylinder z range, on Q side
0224         {
0225             t_cand = nd < 0.f ? t_QCAP : t_min ;  // nd < 0, ray headed downwards (-z) 
0226             checkr = checkr_QCAP ; 
0227         }
0228 
0229         // consider looking from P side thru open PCAP towards the QCAP, 
0230         // the aNEAR will be a long way behind you (due to close to axial ray direction) 
0231         // hence it will be -ve and thus disqualified as PCAP=false 
0232         // ... so t_cand will stay at t_min and thus will fall thru 
0233         // to the 2nd chance intersects 
0234         
0235 
0236         if( t_cand > t_min && checkr < 0.f )
0237         {
0238             isect.w = t_cand ; 
0239             if( t_cand == t_NEAR )
0240             {
0241                 isect.x = N1.x ; 
0242                 isect.y = N1.y ; 
0243                 isect.z = 0.f ; 
0244             } 
0245             else
0246             { 
0247                 float sign = t_cand == t_PCAP ? -1.f : 1.f ; 
0248                 isect.x = sign*dnorm.x ; 
0249                 isect.y = sign*dnorm.y ; 
0250                 isect.z = sign*dnorm.z ; 
0251             }
0252             valid_isect = true ; 
0253             return ; 
0254         }
0255        
0256   
0257         // resume considing P to Q lookthru, the aFAR >> dd and this time QCAP 
0258         // is enabled so t_cand = t_QCAP which yields endcap hit so long as checkr_QCAP
0259         // pans out 
0260         //
0261         // 2nd intersect (as RTCD p198 suggests), as the ray can approach 
0262         // the 2nd endcap from either direction : 
0263         // 
0264 
0265 
0266         if( aFAR > 0.f && aFAR < dd )  // far intersection inside cylinder z range
0267         {
0268             t_cand = t_FAR ; 
0269             checkr = -1.f ; 
0270         } 
0271         else if( aFAR < 0.f ) //  far intersection outside cylinder z range, on P side (-z)
0272         {
0273             t_cand = nd < 0.f ? t_PCAP : t_min ;      // sign flip cf RTCD:p198     
0274             checkr = checkr_PCAP ; 
0275         } 
0276         else if( aFAR > dd ) //  far intersection outside cylinder z range, on Q side (+z)
0277         {
0278             t_cand = nd > 0.f ? t_QCAP : t_min  ;    // sign flip cf RTCD:p198
0279             checkr = checkr_QCAP ;
0280         }
0281 
0282         if( t_cand > t_min && checkr < 0.f )
0283         {
0284             isect.w = t_cand ; 
0285             if( t_cand == t_FAR )
0286             {
0287                 isect.x = N2.x ; 
0288                 isect.y = N2.y ; 
0289                 isect.z = 0.f ; 
0290             } 
0291             else
0292             { 
0293                 float sign = t_cand == t_PCAP ? -1.f : 1.f ; 
0294                 isect.x = sign*dnorm.x ; 
0295                 isect.y = sign*dnorm.y ; 
0296                 isect.z = sign*dnorm.z ; 
0297             } 
0298             valid_isect = true ; 
0299             return ; 
0300         }
0301 
0302     }  // disc > 0.f
0303 
0304     valid_isect = false ; 
0305 }
0306 
0307 
0308