Esempio n. 1
0
int Lemon::Intersect(const Vector3d& P, const Vector3d& D, LEMON_INT *Intersection, TraceThreadData *Thread) const
{
    int i = 0;
    DBL a, b, c[5], r[4];
    DBL d;
    DBL R2,r2, Pz2, Dz2, PDz2, k1, k2, horizontal, vertical, OCSquared;
    int n;

    Vector3d Padj, Second_Center,Ipoint, INormal;

    Second_Center = Vector3d(0, 0, VerticalPosition);
    r2 = Sqr(inner_radius);

    if (HorizontalPosition < -Lemon_Tolerance )
    { // use a torus
        Padj = P - Second_Center;
        R2 = Sqr(HorizontalPosition);

        Pz2 = Padj[Z] * Padj[Z];
        Dz2 = D[Z] * D[Z];
        PDz2 = Padj[Z] * D[Z];

        k1 = Padj[X] * Padj[X] + Padj[Y] * Padj[Y] + Pz2 - R2 - r2;
        k2 = Padj[X] * D[X] + Padj[Y] * D[Y] + PDz2;
        // this is just like a big torus
        c[0] = 1.0;

        c[1] = 4.0 * k2;

        c[2] = 2.0 * (k1 + 2.0 * (k2 * k2 + R2 * Dz2));

        c[3] = 4.0 * (k2 * k1 + 2.0 * R2 * PDz2);

        c[4] = k1 * k1 + 4.0 * R2 * (Pz2 - r2);

        n = Solve_Polynomial(4, c, r, Test_Flag(this, STURM_FLAG), ROOT_TOLERANCE, Thread->Stats());
        while (n--)
        {
            // here we only keep the 'lemon' inside the torus
            // and dismiss the 'apple'
            // If you find a solution to resolve the rotation of
            //   (x + r)^2 + z^2 = R^2 around z (so replacing x by sqrt(x^2+y^2))
            // with something which is faster than a 4th degree polynome,
            // please feel welcome to update and share...

            Ipoint = P + r[n] * D;
            vertical = Ipoint[Z];
            if ((vertical >= 0.0) && (vertical <= 1.0))
            {
                horizontal = sqrt(Sqr(Ipoint[X]) + Sqr(Ipoint[Y]));
                OCSquared = Sqr((horizontal - HorizontalPosition)) + Sqr((vertical - VerticalPosition));
                if (fabs(OCSquared - r2 ) < ROOT_TOLERANCE)
                {
                    Intersection[i].d = r[n];
                    INormal = Ipoint;
                    INormal[Z] -= VerticalPosition;
                    INormal[X] -= (INormal[X] * HorizontalPosition / horizontal);
                    INormal[Y] -= (INormal[Y] * HorizontalPosition / horizontal);
                    INormal.normalize();
                    Intersection[i].n = INormal;
                    ++i;
                }
            }
        }
    }
    else
    {
        // use a sphere, as the center is on the axis
        // keeping a torus would trigger a problem of self-coincidence surface
        DBL OCSquared, t_Closest_Approach, Half_Chord, t_Half_Chord_Squared;
        DBL Depth;
        Vector3d Origin_To_Center;

        Origin_To_Center = Second_Center - P;

        OCSquared = Origin_To_Center.lengthSqr();

        t_Closest_Approach = dot(Origin_To_Center, D);

        if (!((OCSquared >= r2) && (t_Closest_Approach < EPSILON )))
        {

            t_Half_Chord_Squared = r2 - OCSquared + Sqr(t_Closest_Approach);

            if (t_Half_Chord_Squared > EPSILON)
            {
                Half_Chord = sqrt(t_Half_Chord_Squared);
                // first intersection
                Depth = t_Closest_Approach - Half_Chord;
                if((Depth > DEPTH_TOLERANCE) && (Depth < MAX_DISTANCE))
                {

                    Ipoint = P + Depth * D;
                    vertical = Ipoint[Z];
                    if ((vertical >= 0.0) && (vertical <= 1.0))
                    {
                        Intersection[i].d = Depth;
                        INormal = Ipoint;
                        INormal[Z] -= VerticalPosition;
                        INormal.normalize();
                        Intersection[i].n = INormal;
                        ++i;
                    }
                }
                // second intersection
                Depth = t_Closest_Approach + Half_Chord;
                if((Depth > DEPTH_TOLERANCE) && (Depth < MAX_DISTANCE))
                {
                    Ipoint = P + Depth * D;
                    vertical = Ipoint[Z];
                    if ((vertical >= 0.0) && (vertical <= 1.0))
                    {
                        Intersection[i].d = Depth;
                        INormal = Ipoint;
                        INormal[Z] -= VerticalPosition;
                        INormal.normalize();
                        Intersection[i].n = INormal;
                        ++i;
                    }
                }
            }
        }

    }

    // intersection with apex and base disc
    if (Test_Flag(this, CLOSED_FLAG) && (fabs(D[Z]) > EPSILON))
    {
        d = - P[Z] / D[Z];

        a = (P[X] + d * D[X]);

        b = (P[Y] + d * D[Y]);

        if (((Sqr(a) + Sqr(b)) <= Sqr(base_radius)) && (d > Lemon_Tolerance) && (d < MAX_DISTANCE))
        {
            Intersection[i].d   = d ;
            Intersection[i].n = Vector3d(0, 0, -1);
            ++i;
        }

        d = (1.0 - P[Z]) / D[Z];

        a = (P[X] + d * D[X]);

        b = (P[Y] + d * D[Y]);

        if (((Sqr(a) + Sqr(b)) <= Sqr(apex_radius))
                && (d > Lemon_Tolerance) && (d < MAX_DISTANCE))
        {
            Intersection[i].d   = d ;
            Intersection[i].n = Vector3d(0, 0, 1);
            ++i;
        }
    }

    return (i);
}
Esempio n. 2
0
void Ovus::Intersect_Ovus_Spheres(const Vector3d& P, const Vector3d& D,
                                  DBL * Depth1, DBL * Depth2, DBL * Depth3,
                                  DBL * Depth4, DBL * Depth5, DBL * Depth6,
                                  TraceThreadData *Thread) const
{
    DBL OCSquared, t_Closest_Approach, Half_Chord, t_Half_Chord_Squared;
    Vector3d Padj;
    Vector3d IPoint;
    DBL R2, r2, Py2, Dy2, PDy2, k1, k2, horizontal, vertical;
    DBL Rad1, Rad2;
    int n;
    int lcount=0;
    Vector3d Second_Center;
    DBL c[5], r[4];

    *Depth1 = *Depth2 = *Depth3 = *Depth4 = *Depth5 = *Depth6 = -100; // TODO FIXME - magic value
    // no hit unless...

    Padj = -P;
    Rad1 = Sqr(BottomRadius);
    Rad2 = Sqr(TopRadius);
    OCSquared = Padj.lengthSqr();

    t_Closest_Approach = dot(Padj, D);

    if ((OCSquared < Rad1) || (t_Closest_Approach > EPSILON))
    {

        t_Half_Chord_Squared = Rad1 - OCSquared + Sqr(t_Closest_Approach);

        if (t_Half_Chord_Squared > EPSILON)
        {
            Half_Chord = sqrt(t_Half_Chord_Squared);

            *Depth1 = t_Closest_Approach - Half_Chord;
            *Depth2 = t_Closest_Approach + Half_Chord;
            IPoint = P + *Depth1 * D;
            if (IPoint[Y] < BottomVertical)
            {
                lcount++;
            }
            IPoint = P + *Depth2 * D;
            if (IPoint[Y] < BottomVertical)
            {
                lcount++;
            }
        }
    }
    if (lcount > 1) return;
    Second_Center = Vector3d(0, BottomRadius, 0);
    Padj = Second_Center - P;

    OCSquared = Padj.lengthSqr();

    t_Closest_Approach = dot(Padj, D);

    if ((OCSquared < Rad2) || (t_Closest_Approach > EPSILON))
    {

        t_Half_Chord_Squared = Rad2 - OCSquared + Sqr(t_Closest_Approach);

        if (t_Half_Chord_Squared > EPSILON)
        {
            Half_Chord = sqrt(t_Half_Chord_Squared);

            *Depth3 = t_Closest_Approach - Half_Chord;
            *Depth4 = t_Closest_Approach + Half_Chord;
            IPoint = P + *Depth3 * D;
            if (IPoint[Y] > TopVertical)
            {
                lcount++;
            }
            IPoint = P + *Depth4 * D;
            if (IPoint[Y] > TopVertical)
            {
                lcount++;
            }

        }
    }
    if (lcount > 1) return;
    Second_Center = Vector3d(0, VerticalPosition, 0);
    Padj = P - Second_Center;
    R2 = Sqr(HorizontalPosition);
    r2 = Sqr(ConnectingRadius);
    // Notice : ConnectingRadius > HorizontalPosition here !

    Py2 = Padj[Y] * Padj[Y];
    Dy2 = D[Y] * D[Y];
    PDy2 = Padj[Y] * D[Y];

    k1 = Padj[X] * Padj[X] + Padj[Z] * Padj[Z] + Py2 - R2 - r2;
    k2 = Padj[X] * D[X] + Padj[Z] * D[Z] + PDy2;
    // this is just like a big torus
    c[0] = 1.0;

    c[1] = 4.0 * k2;

    c[2] = 2.0 * (k1 + 2.0 * (k2 * k2 + R2 * Dy2));

    c[3] = 4.0 * (k2 * k1 + 2.0 * R2 * PDy2);

    c[4] = k1 * k1 + 4.0 * R2 * (Py2 - r2);

    n = Solve_Polynomial(4, c, r, Test_Flag(this, STURM_FLAG), ROOT_TOLERANCE, Thread->Stats());
    while (n--)
    {
        // here we only keep the 'lemon' inside the torus
        // and dismiss the 'apple'
        // If you find a solution to resolve the rotation of
        //   (x + r)^2 + y^2 = R^2 around y (so replacing x by sqrt(x^2+z^2))
        // with something which is faster than a 4th degree polynome,
        // please feel welcome to update and share...

        IPoint = P + r[n] * D;

        vertical = IPoint[Y];
        if ((vertical > BottomVertical) && (vertical < TopVertical))
        {
            horizontal = sqrt(Sqr(IPoint[X]) + Sqr(IPoint[Z]));
            OCSquared = Sqr((horizontal + HorizontalPosition)) + Sqr((vertical - VerticalPosition));
            if (fabs(OCSquared - Sqr(ConnectingRadius)) < ROOT_TOLERANCE)
            {
                if (*Depth5 < 0)
                {
                    *Depth5 = r[n];
                }
                else
                {
                    *Depth6 = r[n];
                }
            }
        }
    }
}
Esempio n. 3
0
int Torus::Intersect(const Ray& ray, DBL *Depth, SceneThreadData *Thread) const
{
	int i, n;
	DBL len, R2, Py2, Dy2, PDy2, k1, k2;
	DBL y1, y2, r1, r2;
	DBL c[5];
	DBL r[4];
	VECTOR P, D;
	DBL DistanceP;            // Distance from P to torus center (origo).
	DBL BoundingSphereRadius; // Sphere fully (amply) enclosing torus.
	DBL Closer;               // P is moved Closer*D closer to torus.

	Thread->Stats()[Ray_Torus_Tests]++;

	/* Transform the ray into the torus space. */

	MInvTransPoint(P, ray.Origin, Trans);

	MInvTransDirection(D, ray.Direction, Trans);

	VLength(len, D);

	VInverseScaleEq(D, len);

	i = 0;

	y1 = -MinorRadius;
	y2 =  MinorRadius;
	r1 = Sqr(MajorRadius - MinorRadius);

	if ( MajorRadius < MinorRadius )
		r1 = 0;

	r2 = Sqr(MajorRadius + MinorRadius);

#ifdef TORUS_EXTRA_STATS
	Thread->Stats()[Torus_Bound_Tests]++;
#endif

	if (Test_Thick_Cylinder(P, D, y1, y2, r1, r2))
	{
#ifdef TORUS_EXTRA_STATS
		Thread->Stats()[Torus_Bound_Tests_Succeeded]++;
#endif

		// Move P close to bounding sphere to have more precise root calculation.
		// Bounding sphere radius is R + r, we add r once more to ensure
		// that P is safely outside sphere.
		BoundingSphereRadius = MajorRadius + MinorRadius + MinorRadius;
		DistanceP = VSumSqr(P); // Distance is currently squared.
		Closer = 0.0;
		if (DistanceP > Sqr(BoundingSphereRadius))
		{
			DistanceP = sqrt(DistanceP); // Now real distance.
			Closer = DistanceP - BoundingSphereRadius;
			VAddScaledEq(P, Closer, D);
		}

		R2   = Sqr(MajorRadius);
		r2   = Sqr(MinorRadius);

		Py2  = P[Y] * P[Y];
		Dy2  = D[Y] * D[Y];
		PDy2 = P[Y] * D[Y];

		k1   = P[X] * P[X] + P[Z] * P[Z] + Py2 - R2 - r2;
		k2   = P[X] * D[X] + P[Z] * D[Z] + PDy2;

		c[0] = 1.0;

		c[1] = 4.0 * k2;

		c[2] = 2.0 * (k1 + 2.0 * (k2 * k2 + R2 * Dy2));

		c[3] = 4.0 * (k2 * k1 + 2.0 * R2 * PDy2);

		c[4] = k1 * k1 + 4.0 * R2 * (Py2 - r2);

		n = Solve_Polynomial(4, c, r, Test_Flag(this, STURM_FLAG), ROOT_TOLERANCE, Thread);

		while(n--)
			Depth[i++] = (r[n] + Closer) / len;
	}

	if (i)
		Thread->Stats()[Ray_Torus_Tests_Succeeded]++;

	return(i);
}
Esempio n. 4
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);
}
Esempio n. 5
0
bool Lathe::Inside(const Vector3d& IPoint, TraceThreadData *Thread) const
{
    int i, n, NC;
    DBL r, k, w;
    DBL x[4];
    DBL y[3];
    DBL *height;
    Vector3d P;
    BCYL_ENTRY *entry;
    LATHE_SPLINE_ENTRY *Entry;

    height = Spline->BCyl->height;

    entry = Spline->BCyl->entry;

    /* Transform the point into the lathe space. */

    MInvTransPoint(P, IPoint, Trans);

    /* Number of crossings. */

    NC = 0;

    if ((P[Y] >= Height1) && (P[Y] <= Height2))
    {
        r = sqrt(P[X] * P[X] + P[Z] * P[Z]);

        if ((r >= Radius1) && (r <= Radius2))
        {
            for (i = 0; i < Number; i++)
            {
                Entry = &Spline->Entry[i];

                /* Test if we are inside the segments cylindrical bound. */

                if ((P[Y] >= height[entry[i].h1] - EPSILON) &&
                        (P[Y] <= height[entry[i].h2] + EPSILON))
                {
                    x[0] = Entry->A[Y];
                    x[1] = Entry->B[Y];
                    x[2] = Entry->C[Y];
                    x[3] = Entry->D[Y] - P[Y];

                    n = Solve_Polynomial(3, x, y, Test_Flag(this, STURM_FLAG), 0.0, Thread);

                    while (n--)
                    {
                        w = y[n];

                        if ((w >= 0.0) && (w <= 1.0))
                        {
                            k  = w * (w * (w * Entry->A[X] + Entry->B[X]) + Entry->C[X]) + Entry->D[X] - r;

                            if (k >= 0.0)
                            {
                                NC++;
                            }
                        }
                    }
                }
            }
        }
    }

    if (NC & 1)
    {
        return(!Test_Flag(this, INVERTED_FLAG));
    }
    else
    {
        return(Test_Flag(this, INVERTED_FLAG));
    }
}
Esempio n. 6
0
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;
}
Esempio n. 7
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;
}
Esempio n. 8
0
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);
}