Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-12 08:27:02

0001 /**
0002  * Exercises phi intervals baked into centred ZSphere and Cylinder leaves. The
0003  * radial-wall cases are essential: filtering only curved roots would return the
0004  * wrong, later surface.
0005  */
0006 
0007 #include <cmath>
0008 #include <cstdio>
0009 
0010 #include "scuda.h"
0011 #include "squad.h"
0012 
0013 #include "csg_intersect_leaf_head.h"
0014 #include "csg_robust_quadratic_roots.h"
0015 
0016 #include "csg_intersect_leaf_cylinder.h"
0017 #include "csg_intersect_leaf_zsphere.h"
0018 
0019 namespace
0020 {
0021 int failures = 0;
0022 
0023 void check(const char* label, bool condition)
0024 {
0025     std::printf("// %-62s %s\n", label, condition ? "PASS" : "FAIL");
0026     if (!condition)
0027         failures++;
0028 }
0029 
0030 bool close(float actual, float expected, float tolerance = 1.e-3f)
0031 {
0032     return std::fabs(actual - expected) <= tolerance * (1.f + std::fabs(expected));
0033 }
0034 
0035 quad phi_primitive(float startPhi, float deltaPhi, float radius)
0036 {
0037     quad q;
0038     q.f = make_float4(startPhi, deltaPhi, 0.f, radius);
0039     return q;
0040 }
0041 
0042 quad z_range(float z1, float z2)
0043 {
0044     quad q;
0045     q.f = make_float4(z1, z2, 0.f, 0.f);
0046     return q;
0047 }
0048 
0049 struct Result
0050 {
0051     bool   valid;
0052     float4 isect;
0053     float3 hit;
0054 };
0055 
0056 Result sphere(const quad& q0, const quad& q1, const float3& origin, const float3& direction)
0057 {
0058     Result result = {false, make_float4(0.f, 0.f, 0.f, 0.f), make_float3(0.f, 0.f, 0.f)};
0059     intersect_leaf_zsphere(result.valid, result.isect, q0, q1, 0.f, origin, direction);
0060     result.hit = make_float3(
0061         origin.x + result.isect.w * direction.x,
0062         origin.y + result.isect.w * direction.y,
0063         origin.z + result.isect.w * direction.z);
0064     return result;
0065 }
0066 
0067 Result cylinder(const quad& q0, const quad& q1, const float3& origin, const float3& direction)
0068 {
0069     Result result = {false, make_float4(0.f, 0.f, 0.f, 0.f), make_float3(0.f, 0.f, 0.f)};
0070     intersect_leaf_cylinder(result.valid, result.isect, q0, q1, 0.f, origin, direction);
0071     result.hit = make_float3(
0072         origin.x + result.isect.w * direction.x,
0073         origin.y + result.isect.w * direction.y,
0074         origin.z + result.isect.w * direction.z);
0075     return result;
0076 }
0077 
0078 void check_quarter_wedge()
0079 {
0080     const float radius = 100.f;
0081     const float quarter = 0.5f * CUDART_PI_F;
0082     const quad  q0 = phi_primitive(0.f, quarter, radius);
0083     const quad  q1 = z_range(-radius, radius);
0084     const float c = std::cos(0.25f * CUDART_PI_F);
0085     const float s = std::sin(0.25f * CUDART_PI_F);
0086 
0087     Result sr = sphere(q0, q1, make_float3(2.f * radius * c, 2.f * radius * s, 0.f), make_float3(-c, -s, 0.f));
0088     check("quarter ZSphere hits its curved surface", sr.valid && close(sr.hit.x, radius * c) && close(sr.hit.y, radius * s));
0089 
0090     Result cr = cylinder(q0, q1, make_float3(2.f * radius * c, 2.f * radius * s, 0.f), make_float3(-c, -s, 0.f));
0091     check("quarter Cylinder hits its curved surface", cr.valid && close(cr.hit.x, radius * c) && close(cr.hit.y, radius * s));
0092 
0093     sr = sphere(q0, q1, make_float3(-200.f, 50.f, 0.f), make_float3(1.f, 0.f, 0.f));
0094     check("quarter ZSphere first hits the end-phi wall", sr.valid && close(sr.isect.w, 200.f) && close(sr.hit.x, 0.f) && close(sr.isect.x, -1.f));
0095 
0096     cr = cylinder(q0, q1, make_float3(-200.f, 50.f, 0.f), make_float3(1.f, 0.f, 0.f));
0097     check("quarter Cylinder first hits the end-phi wall", cr.valid && close(cr.isect.w, 200.f) && close(cr.hit.x, 0.f) && close(cr.isect.x, -1.f));
0098 
0099     sr = sphere(q0, q1, make_float3(-200.f, -50.f, 0.f), make_float3(1.f, 0.f, 0.f));
0100     cr = cylinder(q0, q1, make_float3(-200.f, -50.f, 0.f), make_float3(1.f, 0.f, 0.f));
0101     check("quarter ZSphere misses a ray wholly outside the wedge", !sr.valid);
0102     check("quarter Cylinder misses a ray wholly outside the wedge", !cr.valid);
0103 
0104     check("quarter ZSphere distance is negative inside", distance_leaf_zsphere(make_float3(50.f, 50.f, 0.f), q0, q1) < 0.f);
0105     check("quarter ZSphere distance is positive outside phi", distance_leaf_zsphere(make_float3(-50.f, 50.f, 0.f), q0, q1) > 0.f);
0106     check("quarter Cylinder distance is negative inside", distance_leaf_cylinder(make_float3(50.f, 50.f, 0.f), q0, q1) < 0.f);
0107     check("quarter Cylinder distance is positive outside phi", distance_leaf_cylinder(make_float3(-50.f, 50.f, 0.f), q0, q1) > 0.f);
0108 }
0109 
0110 void check_caps_and_wrapped_start()
0111 {
0112     const float radius = 100.f;
0113     const float quarter = 0.5f * CUDART_PI_F;
0114     const quad  q0 = phi_primitive(0.f, quarter, radius);
0115     const quad  q1 = z_range(-60.f, 60.f);
0116 
0117     Result sr = sphere(q0, q1, make_float3(20.f, 20.f, 200.f), make_float3(0.f, 0.f, -1.f));
0118     Result cr = cylinder(q0, q1, make_float3(20.f, 20.f, 200.f), make_float3(0.f, 0.f, -1.f));
0119     check("quarter ZSphere accepts an in-wedge z cap", sr.valid && close(sr.hit.z, 60.f) && close(sr.isect.z, 1.f));
0120     check("quarter Cylinder accepts an in-wedge z cap", cr.valid && close(cr.hit.z, 60.f) && close(cr.isect.z, 1.f));
0121 
0122     sr = sphere(q0, q1, make_float3(-20.f, 20.f, 200.f), make_float3(0.f, 0.f, -1.f));
0123     cr = cylinder(q0, q1, make_float3(-20.f, 20.f, 200.f), make_float3(0.f, 0.f, -1.f));
0124     check("quarter ZSphere rejects an out-of-wedge z cap", !sr.valid);
0125     check("quarter Cylinder rejects an out-of-wedge z cap", !cr.valid);
0126 
0127     const quad wrapped = phi_primitive(1.75f * CUDART_PI_F, quarter, radius);
0128     sr = sphere(wrapped, q1, make_float3(200.f, 0.f, 0.f), make_float3(-1.f, 0.f, 0.f));
0129     cr = cylinder(wrapped, q1, make_float3(200.f, 0.f, 0.f), make_float3(-1.f, 0.f, 0.f));
0130     check("wrapped-start ZSphere includes phi zero", sr.valid && close(sr.hit.x, radius));
0131     check("wrapped-start Cylinder includes phi zero", cr.valid && close(cr.hit.x, radius));
0132 }
0133 
0134 void check_pacman_wedge()
0135 {
0136     const float radius = 100.f;
0137     const float delta = 1.5f * CUDART_PI_F;
0138     const quad  q0 = phi_primitive(0.f, delta, radius);
0139     const quad  q1 = z_range(-radius, radius);
0140 
0141     Result sr = sphere(q0, q1, make_float3(200.f, -50.f, 0.f), make_float3(-1.f, 0.f, 0.f));
0142     Result cr = cylinder(q0, q1, make_float3(200.f, -50.f, 0.f), make_float3(-1.f, 0.f, 0.f));
0143     check("pacman ZSphere first hits the end-phi wall", sr.valid && close(sr.hit.x, 0.f) && close(sr.isect.x, 1.f));
0144     check("pacman Cylinder first hits the end-phi wall", cr.valid && close(cr.hit.x, 0.f) && close(cr.isect.x, 1.f));
0145 
0146     check("pacman ZSphere distance is negative in retained region", distance_leaf_zsphere(make_float3(-50.f, -50.f, 0.f), q0, q1) < 0.f);
0147     check("pacman ZSphere distance is positive in missing quadrant", distance_leaf_zsphere(make_float3(50.f, -50.f, 0.f), q0, q1) > 0.f);
0148     check("pacman Cylinder distance is negative in retained region", distance_leaf_cylinder(make_float3(-50.f, -50.f, 0.f), q0, q1) < 0.f);
0149     check("pacman Cylinder distance is positive in missing quadrant", distance_leaf_cylinder(make_float3(50.f, -50.f, 0.f), q0, q1) > 0.f);
0150 }
0151 } // namespace
0152 
0153 int main()
0154 {
0155     check_quarter_wedge();
0156     check_caps_and_wrapped_start();
0157     check_pacman_wedge();
0158     std::printf("// intersect_leaf_phi_wedge_test : %s (%d failure%s)\n", failures == 0 ? "PASS" : "FAIL", failures, failures == 1 ? "" : "s");
0159     return failures == 0 ? 0 : 1;
0160 }