Пример #1
0
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);
}
Пример #2
0
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;
}