00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #ifndef NVBLASTEXTAUTHORINGVSA_H
00030 #define NVBLASTEXTAUTHORINGVSA_H
00031
00032 namespace Nv
00033 {
00034 namespace Blast
00035 {
00036
00037
00038
00039
00040
00041 namespace VSA
00042 {
00043 typedef float real;
00044
00045 struct VS3D_Halfspace_Set
00046 {
00047 virtual real farthest_halfspace(real plane[4], const real point[4]) = 0;
00048 };
00049
00050
00051
00052 struct Vec3 { real x, y, z; };
00053 inline Vec3 vec3(real x, real y, real z) { Vec3 r; r.x = x; r.y = y; r.z = z; return r; }
00054 inline Vec3 operator + (const Vec3& a, const Vec3& b) { return vec3(a.x + b.x, a.y + b.y, a.z + b.z); }
00055 inline Vec3 operator * (real s, const Vec3& v) { return vec3(s*v.x, s*v.y, s*v.z); }
00056 inline real operator | (const Vec3& a, const Vec3& b) { return a.x*b.x + a.y*b.y + a.z*b.z; }
00057 inline Vec3 operator ^ (const Vec3& a, const Vec3& b) { return vec3(a.y*b.z - b.y*a.z, a.z*b.x - b.z*a.x, a.x*b.y - b.x*a.y); }
00058
00059 struct Vec4 { Vec3 v; real w; };
00060 inline Vec4 vec4(const Vec3& v, real w) { Vec4 r; r.v = v; r.w = w; return r; }
00061 inline real operator | (const Vec4& a, const Vec4& b) { return (a.v | b.v) + a.w*b.w; }
00062
00063
00064 inline Vec3 perp(const Vec3& a, const Vec3& b)
00065 {
00066 Vec3 c = a^b;
00067 #if VS3D_HIGH_ACCURACY || REAL_DOUBLE
00068 const real c2 = c | c;
00069 if (c2 != 0) c = c + (1 / c2)*((a | c)*(c^b) + (b | c)*(a^c));
00070 #endif
00071 return c;
00072 }
00073
00074
00075 inline real sq(real x) { return x*x; }
00076
00077
00078 inline int ext_index(int c_10, int c_21, int c_20) { return c_10 << c_21 | (c_21&c_20) << 1; }
00079
00080
00081 inline int index_of_min(real x0, real x1, real x2) { return ext_index((int)(x1 < x0), (int)(x2 < x1), (int)(x2 < x0)); }
00082
00083
00084 inline bool frac_gt(real a_num, real a_rden2, real b_num, real b_rden2)
00085 {
00086 const bool a_num_neg = a_num < 0;
00087 const bool b_num_neg = b_num < 0;
00088 return a_num_neg != b_num_neg ? b_num_neg : ((a_num*a_num*a_rden2 > b_num*b_num*b_rden2) != a_num_neg);
00089 }
00090
00091
00092 inline int index_of_max_frac(real x0_num, real x0_rden2, real x1_num, real x1_rden2, real x2_num, real x2_rden2)
00093 {
00094 return ext_index((int)frac_gt(x1_num, x1_rden2, x0_num, x0_rden2), (int)frac_gt(x2_num, x2_rden2, x1_num, x1_rden2), (int)frac_gt(x2_num, x2_rden2, x0_num, x0_rden2));
00095 }
00096
00097
00098 inline bool sgn_sq_gt(real sgn_a, real a2, real sgn_b, real b2) { return sgn_a*sgn_b < 0 ? (sgn_b < 0) : ((a2 > b2) != (sgn_a < 0)); }
00099
00100
00101 inline int index_of_max_sgn_sq(real sgn_x0, real sq_x0, real sgn_x1, real sq_x1, real sgn_x2, real sq_x2)
00102 {
00103 return ext_index((int)sgn_sq_gt(sgn_x1, sq_x1, sgn_x0, sq_x0), (int)sgn_sq_gt(sgn_x2, sq_x2, sgn_x1, sq_x1), (int)sgn_sq_gt(sgn_x2, sq_x2, sgn_x0, sq_x0));
00104 }
00105
00106
00107 inline void project2D(Vec3& r, const Vec3& plane, real delta, real recip_n2, real eps2)
00108 {
00109 r = r + (-delta*recip_n2)*vec3(plane.x, plane.y, 0);
00110 r = r + (-(r | plane)*recip_n2)*vec3(plane.x, plane.y, 0);
00111 if ((r | r) > eps2) return;
00112 r = (-plane.z*recip_n2)*vec3(plane.x, plane.y, 0);
00113 r.z = 1;
00114 }
00115
00116
00117
00118 static bool vs3d_update(Vec4& p, Vec4 S[4], int& plane_count, const Vec4& q, real eps2)
00119 {
00120
00121 const Vec4& h = S[plane_count - 1];
00122
00123
00124 if (plane_count == 1)
00125 {
00126
00127 p = q;
00128 p.v = p.v + -(p | h)*h.v;
00129 if ((p | p) <= eps2) p = vec4(-h.w*h.v, 1);
00130 return true;
00131 }
00132
00133
00134 const int min_i = index_of_min(h.v.x*h.v.x, h.v.y*h.v.y, h.v.z*h.v.z);
00135 const Vec3 y = h.v^vec3((real)(min_i == 0), (real)(min_i == 1), (real)(min_i == 2));
00136 const Vec3 x = y^h.v;
00137
00138
00139 Vec3 r = { x | q.v, y | q.v, q.w*(y | y) };
00140
00141
00142 if ((r | r) <= eps2) r.z = 1;
00143
00144
00145 int N = 0;
00146 Vec3 R[3];
00147 real recip_n2[3];
00148 real delta[3];
00149 int index[3];
00150 for (int i = 0; i < plane_count - 1; ++i)
00151 {
00152 const Vec3& vi = S[i].v;
00153 const real cos_theta = h.v | vi;
00154 R[N] = vec3(x | vi, y | vi, S[i].w - h.w*cos_theta);
00155 index[N] = i;
00156 const real n2 = R[N].x*R[N].x + R[N].y*R[N].y;
00157 if (n2 >= eps2)
00158 {
00159 const real lin_norm = (real)1.5 - (real)0.5*n2;
00160 R[N] = lin_norm*R[N];
00161 recip_n2[N] = 1 / (R[N].x*R[N].x + R[N].y*R[N].y);
00162 delta[N] = r | R[N];
00163 ++N;
00164 }
00165 else if (cos_theta < 0) return false;
00166 }
00167
00168
00169 switch (N)
00170 {
00171 case 1: one_plane :
00172 if (delta[0] < 0) N = 0;
00173 else project2D(r, R[0], delta[0], recip_n2[0], eps2);
00174 break;
00175 case 2: two_planes :
00176 if (delta[0] < 0 && delta[1] < 0) N = 0;
00177 else
00178 {
00179 const int max_d_index = (int)frac_gt(delta[1], recip_n2[1], delta[0], recip_n2[0]);
00180 project2D(r, R[max_d_index], delta[max_d_index], recip_n2[max_d_index], eps2);
00181 const int min_d_index = max_d_index ^ 1;
00182 const real new_delta_min = r | R[min_d_index];
00183 if (new_delta_min < 0)
00184 {
00185 index[0] = index[max_d_index];
00186 N = 1;
00187 }
00188 else
00189 {
00190
00191 r = perp(R[0], R[1]);
00192 if (r.z*r.z*recip_n2[0] * recip_n2[1] < eps2)
00193 {
00194 if (R[0].x*R[1].x + R[0].y*R[1].y < 0) return false;
00195 goto one_plane;
00196 }
00197 r = (1 / r.z)*r;
00198 }
00199 }
00200 break;
00201 case 3:
00202 if (delta[0] < 0 && delta[1] < 0 && delta[2] < 0) N = 0;
00203 else
00204 {
00205 const Vec3 row_x = { R[0].x, R[1].x, R[2].x };
00206 const Vec3 row_y = { R[0].y, R[1].y, R[2].y };
00207 const Vec3 row_w = { R[0].z, R[1].z, R[2].z };
00208 const Vec3 cof_w = perp(row_x, row_y);
00209 const bool detR_pos = (row_w | cof_w) > 0;
00210 const int nrw_sgn0 = cof_w.x*cof_w.x*recip_n2[1] * recip_n2[2] < eps2 ? 0 : (((int)((cof_w.x > 0) == detR_pos) << 1) - 1);
00211 const int nrw_sgn1 = cof_w.y*cof_w.y*recip_n2[2] * recip_n2[0] < eps2 ? 0 : (((int)((cof_w.y > 0) == detR_pos) << 1) - 1);
00212 const int nrw_sgn2 = cof_w.z*cof_w.z*recip_n2[0] * recip_n2[1] < eps2 ? 0 : (((int)((cof_w.z > 0) == detR_pos) << 1) - 1);
00213
00214 if ((nrw_sgn0 | nrw_sgn1 | nrw_sgn2) >= 0) return false;
00215
00216 const int positive_width_count = ((nrw_sgn0 >> 1) & 1) + ((nrw_sgn1 >> 1) & 1) + ((nrw_sgn2 >> 1) & 1);
00217 if (positive_width_count == 1)
00218 {
00219
00220 const int pos_width_index = ((nrw_sgn1 >> 1) & 1) | (nrw_sgn2 & 2);
00221 R[pos_width_index] = R[2];
00222 recip_n2[pos_width_index] = recip_n2[2];
00223 delta[pos_width_index] = delta[2];
00224 index[pos_width_index] = index[2];
00225 N = 2;
00226 goto two_planes;
00227 }
00228
00229
00230 const int max_d_index = r.z != 0
00231 ? index_of_max_frac(delta[0], recip_n2[0], delta[1], recip_n2[1], delta[2], recip_n2[2])
00232 : index_of_max_sgn_sq(delta[0], -sq(r.x*R[0].y - r.y*R[0].x)*recip_n2[0], delta[1], -sq(r.x*R[1].y - r.y*R[1].x)*recip_n2[1], delta[2], -sq(r.x*R[2].y - r.y*R[2].x)*recip_n2[2]);
00233
00234
00235 project2D(r, R[max_d_index], delta[max_d_index], recip_n2[max_d_index], eps2);
00236 N = 1;
00237 const int index_max = index[max_d_index];
00238
00239
00240
00241 const int finite_width_count = (nrw_sgn0 & 1) + (nrw_sgn1 & 1) + (nrw_sgn2 & 1);
00242 if (finite_width_count >= 2)
00243 {
00244 const int i_remaining[2] = { (1 << max_d_index) & 3, (3 >> max_d_index) ^ 1 };
00245 const int i_select = (int)frac_gt(delta[i_remaining[1]], recip_n2[i_remaining[1]], delta[i_remaining[0]], recip_n2[i_remaining[0]]);
00246 for (int i = 0; i < 2; ++i)
00247 {
00248 const int j = i_remaining[i_select^i];
00249 if ((r | R[j]) >= 0)
00250 {
00251 r = perp(R[max_d_index], R[j]);
00252 r = (1 / r.z)*r;
00253 index[1] = index[j];
00254 N = 2;
00255 break;
00256 }
00257 }
00258 }
00259
00260 index[0] = index_max;
00261 }
00262 break;
00263 }
00264
00265
00266 p = vec4(r.x*x + r.y*y + (-r.z*h.w)*h.v, r.z);
00267
00268
00269 if (N < 2 || index[1] != 0) { for (int i = 0; i < N; ++i) S[i] = S[index[i]]; }
00270 else { const Vec4 temp = S[0]; S[0] = S[index[0]]; S[1] = temp; }
00271 S[N] = h;
00272 plane_count = N + 1;
00273
00274 return true;
00275 }
00276
00277
00278
00279 inline int vs3d_test(VS3D_Halfspace_Set& halfspace_set, real* q = nullptr)
00280 {
00281
00282 const Vec4 objective = q ? (q[3] != 0 ? vec4((1 / q[3])*vec3(q[0], q[1], q[2]), 1) : *(Vec4*)q) : vec4(vec3(0, 0, 0), 1);
00283
00284
00285 const real eps_f = (real)1 / (sizeof(real) == 4 ? (1L << 23) : (1LL << 52));
00286 #if VS3D_HIGH_ACCURACY || REAL_DOUBLE
00287 const real eps = 8 * eps_f;
00288 #else
00289 const real eps = 80 * eps_f;
00290 #endif
00291 const real eps2 = eps*eps;
00292
00293
00294 const int max_iteration_count = 50;
00295
00296
00297 Vec4 S[4];
00298 int plane_count = 0;
00299 Vec4 p = objective;
00300
00301
00302 int result = -1;
00303
00304
00305 for (int i = 0; result < 0 && i < max_iteration_count; ++i)
00306 {
00307 Vec4& plane = S[plane_count++];
00308 real delta = halfspace_set.farthest_halfspace(&plane.v.x, &p.v.x);
00309 #if VS3D_UNNORMALIZED_PLANE_HANDLING != 0
00310 const real recip_norm = vs3d_recip_sqrt(plane.v | plane.v);
00311 plane = vec4(recip_norm*plane.v, recip_norm*plane.w);
00312 delta *= recip_norm;
00313 #endif
00314 if (delta <= 0 || delta*delta <= eps2*(p | p)) result = 1;
00315 else if (!vs3d_update(p, S, plane_count, objective, eps2)) result = 0;
00316 }
00317
00318
00319 if (q) *(Vec4*)q = (p.w != 0) ? vec4((1 / p.w)*p.v, 1) : p;
00320
00321 return result;
00322 }
00323
00324 }
00325
00326 }
00327 }
00328
00329
00330 #endif // ifndef NVBLASTEXTAUTHORINGVSA_H