File indexing completed on 2026-08-12 08:27:02
0001
0002
0003
0004
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 }
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 }