Back to home page

EIC code displayed by LXR

 
 

    


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

0001 #pragma once
0002 
0003 LEAF_FUNC
0004 float distance_leaf_zsphere(const float3& pos, const quad& q0, const quad& q1 )
0005 {
0006     float3 center = make_float3(q0.f);
0007     float radius = q0.f.w;
0008     const float2 zdelta = make_float2(q1.f);
0009     const float z2 = center.z + zdelta.y ; 
0010     const float z1 = center.z + zdelta.x ;    
0011 
0012     float3 p = pos - center;
0013     float sd_sphere = length(p) - radius ; 
0014     float sd_capslab = fmaxf( pos.z - z2 , z1 - pos.z ); 
0015 
0016     float sd = fmaxf( sd_capslab, sd_sphere );    // CSG intersect
0017     return sd ; 
0018 }
0019 
0020 /**
0021 intersect_leaf_zsphere
0022 ------------------------
0023 
0024 HMM: rays that look destined to land near to "apex" have a rare (order 1 in 300k) 
0025 problem of missing the zsphere.  This is probably arising from the upper cap 
0026 implementation acting effectively like cutting a pinhole at the apex. 
0027 
0028 When there is no upper cap perhaps can avoid the problem by setting zmax to beyond the 
0029 apex ? Or could have a different imp for zsphere with lower cap but no upper cap. 
0030 
0031 Note that zsphere with no upper cap is used a lot for PMTs so a simpler imp
0032 for zsphere without upper cut does make sense.  
0033 
0034 NB "z2sph <= zmax" changed from "z2sph < zmax" Aug 29, 2022
0035 
0036 The old inequality caused rare unexpected MISS for rays that would
0037 have been expected to intersect close to the apex of the zsphere  
0038 
0039 See : notes/issues/unexpected_zsphere_miss_from_inside_for_rays_that_would_be_expected_to_intersect_close_to_apex.rst
0040 
0041 **/
0042 
0043 
0044 LEAF_FUNC
0045 void intersect_leaf_zsphere(bool& valid_isect, float4& isect, const quad& q0, const quad& q1, const float& t_min, const float3& ray_origin, const float3& ray_direction )
0046 {
0047     const float3 center = make_float3(q0.f);
0048     float3 O = ray_origin - center;  
0049     float3 D = ray_direction;
0050     const float radius = q0.f.w;
0051 
0052     float b = dot(O, D);               // t of closest approach to sphere center
0053     float c = dot(O, O)-radius*radius; // < 0. indicates ray_origin inside sphere
0054 
0055 #ifdef DEBUG_RECORD
0056     printf("//[intersect_leaf_zsphere radius %10.4f b %10.4f c %10.4f \n", radius, b, c); 
0057 #endif
0058 
0059     if( c > 0.f && b > 0.f )
0060     { 
0061         valid_isect = false ; 
0062         return ; 
0063     }   
0064     // Cannot intersect when ray origin outside sphere and direction away from sphere.
0065     // Whether early exit speeds things up (or slows things down) is another question ... 
0066 
0067     const float2 zdelta = make_float2(q1.f);
0068     const float zmax = center.z + zdelta.y ;   // + 0.1f artificial increase zmax to test apex bug 
0069     const float zmin = center.z + zdelta.x ;    
0070 
0071 #ifdef DEBUG_RECORD
0072     bool with_upper_cut = zmax < radius ; 
0073     bool with_lower_cut = zmin > -radius ; 
0074     printf("// intersect_leaf_zsphere radius %10.4f zmax %10.4f zmin %10.4f  with_upper_cut %d with_lower_cut %d  \n", radius, zmax, zmin, with_upper_cut, with_lower_cut ); 
0075 #endif
0076 
0077 
0078     float d = dot(D, D);               // NB NOT assuming normalized ray_direction
0079 
0080     float t1sph, t2sph, disc, sdisc ;    
0081     robust_quadratic_roots(t1sph, t2sph, disc, sdisc, d, b, c); //  Solving:  d t^2 + 2 b t +  c = 0 
0082 
0083     float z1sph = ray_origin.z + t1sph*ray_direction.z ;  // sphere z intersects
0084     float z2sph = ray_origin.z + t2sph*ray_direction.z ; 
0085 
0086 #ifdef DEBUG_RECORD
0087     printf("// intersect_leaf_zsphere t1sph %10.4f t2sph %10.4f sdisc %10.4f \n", t1sph, t2sph, sdisc ); 
0088     printf("// intersect_leaf_zsphere z1sph %10.4f z2sph %10.4f zmax %10.4f zmin %10.4f sdisc %10.4f \n", z1sph, z2sph, zmax, zmin, sdisc ); 
0089 #endif
0090 
0091     float idz = 1.f/ray_direction.z ; 
0092     float t_QCAP = (zmax - ray_origin.z)*idz ;   // upper cap intersects
0093     float t_PCAP = (zmin - ray_origin.z)*idz ;   // lower cap intersect 
0094 
0095 
0096     float t1cap = fminf( t_QCAP, t_PCAP ) ;      // order cap intersects along the ray 
0097     float t2cap = fmaxf( t_QCAP, t_PCAP ) ;      // t2cap > t1cap 
0098 
0099 #ifdef DEBUG_RECORD
0100     bool t1cap_disqualify = t1cap < t1sph || t1cap > t2sph ; 
0101     bool t2cap_disqualify = t2cap < t1sph || t2cap > t2sph ;  
0102     printf("//intersect_leaf_zsphere t1sph %7.3f t2sph %7.3f t_QCAP %7.3f t_PCAP %7.3f t1cap %7.3f t2cap %7.3f  \n", t1sph, t2sph, t_QCAP, t_PCAP, t1cap, t2cap ); 
0103     printf("//intersect_leaf_zsphere  t1cap_disqualify %d t2cap_disqualify %d \n", t1cap_disqualify, t2cap_disqualify  ); 
0104 #endif
0105 
0106     // disqualify plane intersects outside sphere t range
0107     if(t1cap < t1sph || t1cap > t2sph) t1cap = t_min ; 
0108     if(t2cap < t1sph || t2cap > t2sph) t2cap = t_min ; 
0109 
0110     // hmm somehow is seems unclean to have to use both z and t language
0111 
0112     float t_cand = t_min ; 
0113     if(sdisc > 0.f)
0114     {
0115 
0116 #ifdef DEBUG_RECORD
0117         //std::raise(SIGINT); 
0118 #endif
0119 
0120         if(      t1sph > t_min && z1sph > zmin && z1sph <= zmax )  t_cand = t1sph ;  // t1sph qualified and t1cap disabled or disqualified -> t1sph
0121         else if( t1cap > t_min )                                   t_cand = t1cap ;  // t1cap qualifies -> t1cap 
0122         else if( t2cap > t_min )                                   t_cand = t2cap ;  // t2cap qualifies -> t2cap
0123         else if( t2sph > t_min && z2sph > zmin && z2sph <= zmax)   t_cand = t2sph ;  // t2sph qualifies and t2cap disabled or disqialified -> t2sph
0124     }
0125 
0126     valid_isect = t_cand > t_min ;
0127 #ifdef DEBUG_RECORD
0128     printf("//intersect_leaf_zsphere valid_isect %d t_min %7.3f t1sph %7.3f t1cap %7.3f t2cap %7.3f t2sph %7.3f t_cand %7.3f \n", valid_isect, t_min, t1sph, t1cap, t2cap, t2sph, t_cand ); 
0129 #endif
0130 
0131     if(valid_isect)
0132     {
0133         isect.w = t_cand ;
0134         if( t_cand == t1sph || t_cand == t2sph)
0135         {
0136             isect.x = (O.x + t_cand*D.x)/radius ; // normalized by construction
0137             isect.y = (O.y + t_cand*D.y)/radius ;
0138             isect.z = (O.z + t_cand*D.z)/radius ;
0139         }
0140         else
0141         {
0142             isect.x = 0.f ;
0143             isect.y = 0.f ;
0144             isect.z = t_cand == t_PCAP ? -1.f : 1.f ;
0145         }
0146     }
0147 
0148 #ifdef DEBUG_RECORD
0149     printf("//]intersect_leaf_zsphere valid_isect %d \n", valid_isect ); 
0150 #endif
0151 }
0152 
0153