bool Lathe::Intersect(const BasicRay& ray, IStack& Depth_Stack, TraceThreadData *Thread) { int cnt; int found, j, n1, n2; DBL k, len, r, m, w, Dy2, r0, Dylen; DBL x1[7]; DBL x2[3]; DBL y1[6]; DBL y2[2]; DBL best; Vector3d P, D; LATHE_SPLINE_ENTRY *Entry; // Transform the ray into the lathe space. MInvTransPoint(P, ray.Origin, Trans); MInvTransDirection(D, ray.Direction, Trans); len = D.length(); D /= len; Dylen = D[Y] * len; // TODO FIXME - why don't we do this *before* normalizing, saving us the multiplication by len? #ifdef LATHE_EXTRA_STATS Thread->Stats()[Lathe_Bound_Tests]++; #endif // Test if ray misses lathe's cylindrical bound. if(((D[Y] >= 0.0) && (P[Y] > Height2)) || ((D[Y] <= 0.0) && (P[Y] < Height1)) || ((D[X] >= 0.0) && (P[X] > Radius2)) || ((D[X] <= 0.0) && (P[X] < -Radius2))) return false; // Get distance r0 of the ray from rotation axis (i.e. y axis). r0 = fabs(P[X] * D[Z] - P[Z] * D[X]); r = D[X] * D[X] + D[Z] * D[Z]; if(r > 0.0) r0 /= sqrt(r); // Test if ray misses lathe's cylindrical bound. if(r0 > Radius2) return false; // Intersect all cylindrical bounds. BCYL_INT *intervals = reinterpret_cast<BCYL_INT *>(Thread->BCyl_Intervals) ; BCYL_INT *rint = reinterpret_cast<BCYL_INT *>(Thread->BCyl_RInt) ; BCYL_INT *hint = reinterpret_cast<BCYL_INT *>(Thread->BCyl_HInt) ; if((cnt = Intersect_BCyl(Spline->BCyl, intervals, rint, hint, P, D)) == 0) return false; #ifdef LATHE_EXTRA_STATS Thread->Stats()[Lathe_Bound_Tests_Succeeded]++; #endif // Precalculate some constants that are ray-dependant only. m = D[X] * P[X] + D[Z] * P[Z]; Dy2 = D[Y] * D[Y]; // Step through the list of intersections. found = false; best = BOUND_HUGE; for(j = 0; j < cnt; j++) { // Get current segment. Entry = &Spline->Entry[intervals[j].n]; // If we already have the best intersection we may exit. if(!(Type & IS_CHILD_OBJECT) && (intervals[j].d[0] > best)) break; // Init number of roots found. n1 = 0; // Intersect segment. switch(Spline_Type) { // Linear spline case LINEAR_SPLINE: // Solve 2th order polynomial. x1[0] = Entry->C[Y] * Entry->C[Y] * r - Entry->C[X] * Entry->C[X] * Dy2; x1[1] = 2.0 * (Entry->C[Y] * ((Entry->D[Y] - P[Y]) * r + D[Y] * m) - Entry->C[X] * Entry->D[X] * Dy2); x1[2] = (Entry->D[Y] - P[Y]) * ((Entry->D[Y] - P[Y]) * r + 2.0 * D[Y] * m) + Dy2 * (P[X] * P[X] + P[Z] * P[Z] - Entry->D[X] * Entry->D[X]); n1 = Solve_Polynomial(2, x1, y1, false, 0.0, Thread); break; // Quadratic spline case QUADRATIC_SPLINE: // Solve 4th order polynomial. x1[0] = Entry->B[Y] * Entry->B[Y] * r - Entry->B[X] * Entry->B[X] * Dy2; x1[1] = 2.0 * (Entry->B[Y] * Entry->C[Y] * r - Entry->B[X] * Entry->C[X] * Dy2); x1[2] = r * (2.0 * Entry->B[Y] * (Entry->D[Y] - P[Y]) + Entry->C[Y] * Entry->C[Y]) + 2.0 * Entry->B[Y] * D[Y] * m - (2.0 * Entry->B[X] * Entry->D[X] + Entry->C[X] * Entry->C[X]) * Dy2; x1[3] = 2.0 * (Entry->C[Y] * ((Entry->D[Y] - P[Y]) * r + D[Y] * m) - Entry->C[X] * Entry->D[X] * Dy2); x1[4] = (Entry->D[Y] - P[Y]) * ((Entry->D[Y] - P[Y]) * r + 2.0 * D[Y] * m) + Dy2 * (P[X] * P[X] + P[Z] * P[Z] - Entry->D[X] * Entry->D[X]); n1 = Solve_Polynomial(4, x1, y1, Test_Flag(this, STURM_FLAG), 0.0, Thread); break; // Cubic spline case BEZIER_SPLINE: case CUBIC_SPLINE: // Solve 6th order polynomial. x1[0] = Entry->A[Y] * Entry->A[Y] * r - Entry->A[X] * Entry->A[X] * Dy2; x1[1] = 2.0 * (Entry->A[Y] * Entry->B[Y] * r - Entry->A[X] * Entry->B[X] * Dy2); x1[2] = (2.0 * Entry->A[Y] * Entry->C[Y] + Entry->B[Y] * Entry->B[Y]) * r - (2.0 * Entry->A[X] * Entry->C[X] + Entry->B[X] * Entry->B[X]) * Dy2; x1[3] = 2.0 * ((Entry->A[Y] * Entry->D[Y] + Entry->B[Y] * Entry->C[Y] - Entry->A[Y] * P[Y]) * r + Entry->A[Y] * D[Y] * m - (Entry->A[X] * Entry->D[X] + Entry->B[X] * Entry->C[X]) * Dy2); x1[4] = (2.0 * Entry->B[Y] * (Entry->D[Y] - P[Y]) + Entry->C[Y] * Entry->C[Y]) * r + 2.0 * Entry->B[Y] * D[Y] * m - (2.0 * Entry->B[X] * Entry->D[X] + Entry->C[X] * Entry->C[X]) * Dy2; x1[5] = 2.0 * (Entry->C[Y] * ((Entry->D[Y] - P[Y]) * r + D[Y] * m) - Entry->C[X] * Entry->D[X] * Dy2); x1[6] = (Entry->D[Y] - P[Y]) * ((Entry->D[Y] - P[Y]) * r + 2.0 * D[Y] * m) + Dy2 * (P[X] * P[X] + P[Z] * P[Z] - Entry->D[X] * Entry->D[X]); n1 = Solve_Polynomial(6, x1, y1, Test_Flag(this, STURM_FLAG), 0.0, Thread); break; } // Test roots for valid intersections. while(n1--) { w = y1[n1]; if((w >= 0.0) && (w <= 1.0)) { if(fabs(D[Y]) > EPSILON) { k = (w * (w * (w * Entry->A[Y] + Entry->B[Y]) + Entry->C[Y]) + Entry->D[Y] - P[Y]); if (test_hit(ray, Depth_Stack, k / Dylen, w, intervals[j].n, Thread)) { found = true; k /= D[Y]; if (k < best) best = k; } } else { k = w * (w * (w * Entry->A[X] + Entry->B[X]) + Entry->C[X]) + Entry->D[X]; x2[0] = r; x2[1] = 2.0 * m; x2[2] = P[X] * P[X] + P[Z] * P[Z] - k * k; n2 = Solve_Polynomial(2, x2, y2, false, 0.0, Thread); while(n2--) { k = y2[n2]; if(test_hit(ray, Depth_Stack, k / len, w, intervals[j].n, Thread)) { found = true; if(k < best) best = k; } } } } } } return found; }
bool Sor::Intersect(const BasicRay& ray, IStack& Depth_Stack, TraceThreadData *Thread) { int cnt; int found, j, n; DBL a, b, k, h, len, u, v, r0; DBL x[4]; DBL y[3]; DBL best; Vector3d P, D; SOR_SPLINE_ENTRY *Entry; /* Transform the ray into the surface of revolution space. */ MInvTransPoint(P, ray.Origin, Trans); MInvTransDirection(D, ray.Direction, Trans); len = D.length(); D /= len; /* Test if ray misses object's bounds. */ #ifdef SOR_EXTRA_STATS Thread->Stats()[Sor_Bound_Tests]++; #endif if (((D[Y] >= 0.0) && (P[Y] > Height2)) || ((D[Y] <= 0.0) && (P[Y] < Height1)) || ((D[X] >= 0.0) && (P[X] > Radius2)) || ((D[X] <= 0.0) && (P[X] < -Radius2))) { return(false); } /* Get distance of the ray from rotation axis (= y axis). */ r0 = P[X] * D[Z] - P[Z] * D[X]; if ((a = D[X] * D[X] + D[Z] * D[Z]) > 0.0) { r0 /= sqrt(a); } /* Test if ray misses object's bounds. */ if (r0 > Radius2) { return(false); } /* Test base/cap plane. */ found = false; best = BOUND_HUGE; if (Test_Flag(this, CLOSED_FLAG) && (fabs(D[Y]) > EPSILON)) { /* Test base plane. */ if (Base_Radius_Squared > DEPTH_TOLERANCE) { k = (Height1 - P[Y]) / D[Y]; u = P[X] + k * D[X]; v = P[Z] + k * D[Z]; b = u * u + v * v; if (b <= Base_Radius_Squared) { if (test_hit(ray, Depth_Stack, k / len, k, BASE_PLANE, 0, Thread)) { found = true; if (k < best) { best = k; } } } } /* Test cap plane. */ if (Cap_Radius_Squared > DEPTH_TOLERANCE) { k = (Height2 - P[Y]) / D[Y]; u = P[X] + k * D[X]; v = P[Z] + k * D[Z]; b = u * u + v * v; if (b <= Cap_Radius_Squared) { if (test_hit(ray, Depth_Stack, k / len, k, CAP_PLANE, 0, Thread)) { found = true; if (k < best) { best = k; } } } } } /* Intersect all cylindrical bounds. */ vector<BCYL_INT>& intervals = Thread->BCyl_Intervals; vector<BCYL_INT>& rint = Thread->BCyl_RInt; vector<BCYL_INT>& hint = Thread->BCyl_HInt; if ((cnt = Intersect_BCyl(Spline->BCyl, intervals, rint, hint, P, D)) == 0) { #ifdef SOR_EXTRA_STATS if (found) Thread->Stats()[Sor_Bound_Tests_Succeeded]++; #endif return(found); } #ifdef SOR_EXTRA_STATS Thread->Stats()[Sor_Bound_Tests_Succeeded]++; #endif /* Step through the list of intersections. */ for (j = 0; j < cnt; j++) { /* Get current segment. */ Entry = &Spline->Entry[intervals[j].n]; /* If we already have the best intersection we may exit. */ if (!(Type & IS_CHILD_OBJECT) && (intervals[j].d[0] > best)) { break; } /* Cubic curve. */ x[0] = Entry->A * D[Y] * D[Y] * D[Y]; /* x[1] = D[Y] * D[Y] * (3.0 * Entry->A * P[Y] + Entry->B) - D[X] * D[X] - D[Z] * D[Z]; */ x[1] = D[Y] * D[Y] * (3.0 * Entry->A * P[Y] + Entry->B) - a; x[2] = D[Y] * (P[Y] * (3.0 * Entry->A * P[Y] + 2.0 * Entry->B) + Entry->C) - 2.0 * (P[X] * D[X] + P[Z] * D[Z]); x[3] = P[Y] * (P[Y] * (Entry->A * P[Y] + Entry->B) + Entry->C) + Entry->D - P[X] * P[X] - P[Z] * P[Z]; n = Solve_Polynomial(3, x, y, Test_Flag(this, STURM_FLAG), 0.0, Thread); while (n--) { k = y[n]; h = P[Y] + k * D[Y]; if ((h >= Spline->BCyl->height[Spline->BCyl->entry[intervals[j].n].h1]) && (h <= Spline->BCyl->height[Spline->BCyl->entry[intervals[j].n].h2])) { if (test_hit(ray, Depth_Stack, k / len, k, CURVE, intervals[j].n, Thread)) { found = true; if (y[n] < best) { best = k; } } } } } return(found); }