void Lathe::Compute_Lathe(Vector2d *P, TraceThreadData *Thread) { int i, i1, i2, i3, n, segment, number_of_segments; DBL x[4], y[4]; DBL c[3]; DBL r[2]; DBL xmin, xmax, ymin, ymax; DBL *tmp_r1; DBL *tmp_r2; DBL *tmp_h1; DBL *tmp_h2; Vector2d A, B, C, D; /* Get number of segments. */ switch (Spline_Type) { case LINEAR_SPLINE: number_of_segments = Number - 1; break; case QUADRATIC_SPLINE: number_of_segments = Number - 2; break; case CUBIC_SPLINE: number_of_segments = Number - 3; break; case BEZIER_SPLINE: number_of_segments = Number / 4; break; default: /* tw */ number_of_segments = 0; /* tw */ } /* Allocate segments. */ if (Spline == NULL) { Spline = reinterpret_cast<LATHE_SPLINE *>(POV_MALLOC(sizeof(LATHE_SPLINE), "spline segments of lathe")); /* Init spline. */ Spline->References = 1; Spline->Entry = reinterpret_cast<LATHE_SPLINE_ENTRY *>(POV_MALLOC(number_of_segments*sizeof(LATHE_SPLINE_ENTRY), "spline segments of lathe")); } else { /* This should never happen! */ throw POV_EXCEPTION_STRING("Lathe segments are already defined."); } /* Allocate temporary lists. */ tmp_r1 = reinterpret_cast<DBL *>(POV_MALLOC(number_of_segments * sizeof(DBL), "temp lathe data")); tmp_r2 = reinterpret_cast<DBL *>(POV_MALLOC(number_of_segments * sizeof(DBL), "temp lathe data")); tmp_h1 = reinterpret_cast<DBL *>(POV_MALLOC(number_of_segments * sizeof(DBL), "temp lathe data")); tmp_h2 = reinterpret_cast<DBL *>(POV_MALLOC(number_of_segments * sizeof(DBL), "temp lathe data")); /*************************************************************************** * Calculate segments. ****************************************************************************/ /* We want to know the size of the overall bounding cylinder. */ xmax = ymax = -BOUND_HUGE; xmin = ymin = BOUND_HUGE; for (i = segment = 0; segment < number_of_segments; ) { i1 = i + 1; i2 = i + 2; i3 = i + 3; switch (Spline_Type) { /************************************************************************* * Linear spline (nothing more than a simple polygon). **************************************************************************/ case LINEAR_SPLINE: /* Use linear interpolation. */ A = Vector2d(0.0); B = Vector2d(0.0); C = -1.0 * P[i] + 1.0 * P[i1]; D = 1.0 * P[i]; /* Get maximum coordinates in current segment. */ x[0] = x[2] = P[i][X]; x[1] = x[3] = P[i1][X]; y[0] = y[2] = P[i][Y]; y[1] = y[3] = P[i1][Y]; break; /************************************************************************* * Quadratic spline. **************************************************************************/ case QUADRATIC_SPLINE: /* Use quadratic interpolation. */ A = Vector2d(0.0); B = 0.5 * P[i] - 1.0 * P[i1] + 0.5 * P[i2]; C = -0.5 * P[i] + 0.5 * P[i2]; D = 1.0 * P[i1]; /* Get maximum coordinates in current segment. */ x[0] = x[2] = P[i1][X]; x[1] = x[3] = P[i2][X]; y[0] = y[2] = P[i1][Y]; y[1] = y[3] = P[i2][Y]; break; /************************************************************************* * Cubic spline. **************************************************************************/ case CUBIC_SPLINE: /* Use cubic interpolation. */ A = -0.5 * P[i] + 1.5 * P[i1] - 1.5 * P[i2] + 0.5 * P[i3]; B = P[i] - 2.5 * P[i1] + 2.0 * P[i2] - 0.5 * P[i3]; C = -0.5 * P[i] + 0.5 * P[i2]; D = P[i1]; /* Get maximum coordinates in current segment. */ x[0] = x[2] = P[i1][X]; x[1] = x[3] = P[i2][X]; y[0] = y[2] = P[i1][Y]; y[1] = y[3] = P[i2][Y]; break; /************************************************************************* * Bezier spline. **************************************************************************/ case BEZIER_SPLINE: /* Use Bernstein interpolation. */ A = P[i3] - 3.0 * P[i2] + 3.0 * P[i1] - P[i]; B = 3.0 * P[i2] - 6.0 * P[i1] + 3.0 * P[i]; C = 3.0 * P[i1] - 3.0 * P[i]; D = P[i]; x[0] = P[i][X]; x[1] = P[i1][X]; x[2] = P[i2][X]; x[3] = P[i3][X]; y[0] = P[i][Y]; y[1] = P[i1][Y]; y[2] = P[i2][Y]; y[3] = P[i3][Y]; break; default: throw POV_EXCEPTION_STRING("Unknown lathe type in Compute_Lathe()."); } Spline->Entry[segment].A = A; Spline->Entry[segment].B = B; Spline->Entry[segment].C = C; Spline->Entry[segment].D = D; if ((Spline_Type == QUADRATIC_SPLINE) || (Spline_Type == CUBIC_SPLINE)) { /* Get maximum coordinates in current segment. */ c[0] = 3.0 * A[X]; c[1] = 2.0 * B[X]; c[2] = C[X]; n = Solve_Polynomial(2, c, r, false, 0.0, Thread); while (n--) { if ((r[n] >= 0.0) && (r[n] <= 1.0)) { x[n] = r[n] * (r[n] * (r[n] * A[X] + B[X]) + C[X]) + D[X]; } } c[0] = 3.0 * A[Y]; c[1] = 2.0 * B[Y]; c[2] = C[Y]; n = Solve_Polynomial(2, c, r, false, 0.0, Thread); while (n--) { if ((r[n] >= 0.0) && (r[n] <= 1.0)) { y[n] = r[n] * (r[n] * (r[n] * A[Y] + B[Y]) + C[Y]) + D[Y]; } } } /* Set current segment's bounding cylinder. */ tmp_r1[segment] = min(min(x[0], x[1]), min(x[2], x[3])); tmp_r2[segment] = max(max(x[0], x[1]), max(x[2], x[3])); tmp_h1[segment] = min(min(y[0], y[1]), min(y[2], y[3])); tmp_h2[segment] = max(max(y[0], y[1]), max(y[2], y[3])); /* Keep track of overall bounding cylinder. */ xmin = min(xmin, tmp_r1[segment]); xmax = max(xmax, tmp_r2[segment]); ymin = min(ymin, tmp_h1[segment]); ymax = max(ymax, tmp_h2[segment]); /* fprintf(stderr, "bound spline segment %d: ", i); fprintf(stderr, "r = %f - %f, h = %f - %f\n", tmp_r1[segment], tmp_r2[segment], tmp_h1[segment], tmp_h2[segment]); */ /* Advance to next segment. */ switch (Spline_Type) { case LINEAR_SPLINE: case QUADRATIC_SPLINE: case CUBIC_SPLINE: i++; break; case BEZIER_SPLINE: i += 4; break; } segment++; } Number = number_of_segments; /* Set overall bounding cylinder. */ Radius1 = xmin; Radius2 = xmax; Height1 = ymin; Height2 = ymax; /* Get bounding cylinder. */ Spline->BCyl = Create_BCyl(Number, tmp_r1, tmp_r2, tmp_h1, tmp_h2); /* Get rid of temp. memory. */ POV_FREE(tmp_h2); POV_FREE(tmp_h1); POV_FREE(tmp_r2); POV_FREE(tmp_r1); }
void Sor::Compute_Sor(Vector2d *P, TraceThreadData *Thread) { int i, n; DBL *tmp_r1; DBL *tmp_r2; DBL *tmp_h1; DBL *tmp_h2; DBL A, B, C, D, w; DBL xmax, xmin, ymax, ymin; DBL k[4], x[4]; DBL y[2], r[2]; DBL c[3]; MATRIX Mat; /* Allocate Number segments. */ if (Spline == NULL) { Spline = new SOR_SPLINE; Spline->References = 1; Spline->Entry = new SOR_SPLINE_ENTRY[Number]; } else { throw POV_EXCEPTION_STRING("Surface of revolution segments are already defined."); } /* Allocate temporary lists. */ tmp_r1 = new DBL[Number]; tmp_r2 = new DBL[Number]; tmp_h1 = new DBL[Number]; tmp_h2 = new DBL[Number]; /* We want to know the size of the overall bounding cylinder. */ xmax = ymax = -BOUND_HUGE; xmin = ymin = BOUND_HUGE; /* Calculate segments, i.e. cubic patches. */ for (i = 0; i < Number; i++) { if ((fabs(P[i+2][Y] - P[i][Y]) < EPSILON) || (fabs(P[i+3][Y] - P[i+1][Y]) < EPSILON)) { throw POV_EXCEPTION_STRING("Incorrect point in surface of revolution."); } /* Use cubic interpolation. */ k[0] = P[i+1][X] * P[i+1][X]; k[1] = P[i+2][X] * P[i+2][X]; k[2] = (P[i+2][X] - P[i][X]) / (P[i+2][Y] - P[i][Y]); k[3] = (P[i+3][X] - P[i+1][X]) / (P[i+3][Y] - P[i+1][Y]); k[2] *= 2.0 * P[i+1][X]; k[3] *= 2.0 * P[i+2][X]; w = P[i+1][Y]; Mat[0][0] = w * w * w; Mat[0][1] = w * w; Mat[0][2] = w; Mat[0][3] = 1.0; Mat[2][0] = 3.0 * w * w; Mat[2][1] = 2.0 * w; Mat[2][2] = 1.0; Mat[2][3] = 0.0; w = P[i+2][Y]; Mat[1][0] = w * w * w; Mat[1][1] = w * w; Mat[1][2] = w; Mat[1][3] = 1.0; Mat[3][0] = 3.0 * w * w; Mat[3][1] = 2.0 * w; Mat[3][2] = 1.0; Mat[3][3] = 0.0; MInvers(Mat, Mat); /* Calculate coefficients of cubic patch. */ A = k[0] * Mat[0][0] + k[1] * Mat[0][1] + k[2] * Mat[0][2] + k[3] * Mat[0][3]; B = k[0] * Mat[1][0] + k[1] * Mat[1][1] + k[2] * Mat[1][2] + k[3] * Mat[1][3]; C = k[0] * Mat[2][0] + k[1] * Mat[2][1] + k[2] * Mat[2][2] + k[3] * Mat[2][3]; D = k[0] * Mat[3][0] + k[1] * Mat[3][1] + k[2] * Mat[3][2] + k[3] * Mat[3][3]; if (fabs(A) < EPSILON) A = 0.0; if (fabs(B) < EPSILON) B = 0.0; if (fabs(C) < EPSILON) C = 0.0; if (fabs(D) < EPSILON) D = 0.0; Spline->Entry[i].A = A; Spline->Entry[i].B = B; Spline->Entry[i].C = C; Spline->Entry[i].D = D; /* Get minimum and maximum radius**2 in current segment. */ y[0] = P[i+1][Y]; y[1] = P[i+2][Y]; x[0] = x[2] = P[i+1][X]; x[1] = x[3] = P[i+2][X]; c[0] = 3.0 * A; c[1] = 2.0 * B; c[2] = C; n = Solve_Polynomial(2, c, r, false, 0.0, Thread); while (n--) { if ((r[n] >= y[0]) && (r[n] <= y[1])) { x[n] = sqrt(r[n] * (r[n] * (r[n] * A + B) + C) + D); } } /* Set current segment's bounding cylinder. */ tmp_r1[i] = min(min(x[0], x[1]), min(x[2], x[3])); tmp_r2[i] = max(max(x[0], x[1]), max(x[2], x[3])); tmp_h1[i] = y[0]; tmp_h2[i] = y[1]; /* Keep track of overall bounding cylinder. */ xmin = min(xmin, tmp_r1[i]); xmax = max(xmax, tmp_r2[i]); ymin = min(ymin, tmp_h1[i]); ymax = max(ymax, tmp_h2[i]); /* fprintf(stderr, "bound spline segment %d: ", i); fprintf(stderr, "r = %f - %f, h = %f - %f\n", tmp_r1[i], tmp_r2[i], tmp_h1[i], tmp_h2[i]); */ } /* Set overall bounding cylinder. */ Radius1 = xmin; Radius2 = xmax; Height1 = ymin; Height2 = ymax; /* Get cap radius. */ w = tmp_h2[Number-1]; A = Spline->Entry[Number-1].A; B = Spline->Entry[Number-1].B; C = Spline->Entry[Number-1].C; D = Spline->Entry[Number-1].D; if ((Cap_Radius_Squared = w * (w * (A * w + B) + C) + D) < 0.0) { Cap_Radius_Squared = 0.0; } /* Get base radius. */ w = tmp_h1[0]; A = Spline->Entry[0].A; B = Spline->Entry[0].B; C = Spline->Entry[0].C; D = Spline->Entry[0].D; if ((Base_Radius_Squared = w * (w * (A * w + B) + C) + D) < 0.0) { Base_Radius_Squared = 0.0; } /* Get bounding cylinder. */ Spline->BCyl = Create_BCyl(Number, tmp_r1, tmp_r2, tmp_h1, tmp_h2); /* Get rid of temp. memory. */ delete[] tmp_h2; delete[] tmp_h1; delete[] tmp_r2; delete[] tmp_r1; }