Beispiel #1
0
void ContainedBySphere::Normal(const Vector3d& point, const TRANSFORM* pTrans, int side, Vector3d& rNormal) const
{
    Vector3d newPoint;

    /* Transform the point into the isosurface space */
    if(pTrans != NULL)
        MInvTransPoint(newPoint, point, pTrans);
    else
        newPoint = point;

    rNormal = (newPoint - center) / radius;

    /* Transform the normal into the world space. */
    if(pTrans != NULL)
    {
        MTransNormal(rNormal, rNormal, pTrans);

        rNormal.normalize();
    }
}
Beispiel #2
0
bool Superellipsoid::Inside(const Vector3d& IPoint, TraceThreadData *Thread) const
{
    DBL val;
    Vector3d P;

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

    MInvTransPoint(P, IPoint, Trans);

    val = evaluate_superellipsoid(P);

    if (val < EPSILON)
    {
        return(!Test_Flag(this, INVERTED_FLAG));
    }
    else
    {
        return(Test_Flag(this, INVERTED_FLAG));
    }
}
Beispiel #3
0
bool Lemon::All_Intersections(const Ray& ray, IStack& Depth_Stack, TraceThreadData *Thread)
{
    bool Intersection_Found;
    int cnt, i;
    Vector3d Real_Normal;
    Vector3d Real_Pt,INormal;
    LEMON_INT I[4];
    Vector3d P,D;
    DBL len;

    Thread->Stats()[Ray_Lemon_Tests]++;
    MInvTransPoint(P, ray.Origin, Trans);
    MInvTransDirection(D, ray.Direction, Trans);
    len = D.length();
    D /= len;

    Intersection_Found = false;

    if ((cnt = Intersect(P, D, I, Thread)) != 0)
    {
        for (i = 0; i < cnt; i++)
        {
            Real_Pt = ray.Origin + I[i].d/len * ray.Direction;

            if (Clip.empty() || Point_In_Clip(Real_Pt, Clip, Thread))
            {
                INormal = I[i].n;
                MTransNormal(Real_Normal, INormal, Trans);
                Real_Normal.normalize();

                Depth_Stack->push(Intersection(I[i].d/len,Real_Pt,Real_Normal,this));
                Intersection_Found = true;
            }
        }
    }
    if(Intersection_Found)
    {
        Thread->Stats()[Ray_Lemon_Tests_Succeeded]++;
    }
    return (Intersection_Found);
}
Beispiel #4
0
bool Disc::Inside(const Vector3d& IPoint, TraceThreadData *Thread) const
{
    Vector3d New_Point;

    /* Transform the point into the discs space */

    MInvTransPoint(New_Point, IPoint, Trans);

    if (New_Point[Z] >= 0.0)
    {
        /* We are outside. */

        return (Test_Flag(this, INVERTED_FLAG));
    }
    else
    {
        /* We are inside. */

        return (!Test_Flag(this, INVERTED_FLAG));
    }
}
Beispiel #5
0
bool SpindleTorus::All_Intersections(const Ray& ray, IStack& Depth_Stack, TraceThreadData *Thread)
{
    int i, max_i, Found;
    DBL Depth[4];
    Vector3d IPoint;

    Found = false;

    if ((max_i = Intersect(ray, Depth, Thread)) > 0)
    {
        for (i = 0; i < max_i; i++)
        {
            if ((Depth[i] > DEPTH_TOLERANCE) && (Depth[i] < MAX_DISTANCE))
            {
                IPoint = ray.Evaluate(Depth[i]);

                if (Clip.empty() || Point_In_Clip(IPoint, Clip, Thread))
                {
                    // To test whether the point is on the spindle,
                    // we test whether it is inside a sphere around the origin going through the spindle's tips.

                    Vector3d P;
                    MInvTransPoint(P, IPoint, Trans);
                    bool onSpindle = (P.lengthSqr() < mSpindleTipYSqr);

                    bool validIntersection = (onSpindle ? (mSpindleMode & SpindleVisible)
                                                        : (mSpindleMode & NonSpindleVisible));

                    if (validIntersection)
                    {
                        Depth_Stack->push(Intersection(Depth[i], IPoint, this, P, onSpindle));
                        Found = true;
                    }
                }
            }
        }
    }

    return(Found);
}
Beispiel #6
0
static int Inside_Disc (VECTOR IPoint, OBJECT *Object)
{
  VECTOR New_Point;
  DISC *disc = (DISC *) Object;

  /* Transform the point into the discs space */

  MInvTransPoint(New_Point, IPoint, disc->Trans);

  if (New_Point[Z] >= 0.0)
  {
    /* We are outside. */

    return (Test_Flag(disc, INVERTED_FLAG));
  }
  else
  {
    /* We are inside. */

    return (!Test_Flag(disc, INVERTED_FLAG));
  }
}
Beispiel #7
0
bool Torus::Inside(const VECTOR IPoint, TraceThreadData *Thread) const
{
	DBL r, r2;
	VECTOR P;

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

	MInvTransPoint(P, IPoint, Trans);

	r  = sqrt(Sqr(P[X]) + Sqr(P[Z]));

	r2 = Sqr(P[Y]) + Sqr(r - MajorRadius);

	if (r2 <= Sqr(MinorRadius))
	{
		return(!Test_Flag(this, INVERTED_FLAG));
	}
	else
	{
		return(Test_Flag(this, INVERTED_FLAG));
	}
}
Beispiel #8
0
bool Ovus::Inside(const Vector3d& IPoint, TraceThreadData *Thread) const
{
    DBL OCSquared;
    DBL horizontal, vertical;
    bool INSide = false;
    Vector3d Origin, New_Point, Other;
    Origin = Vector3d(0, BottomRadius, 0);
    MInvTransPoint(New_Point, IPoint, Trans);
    OCSquared = New_Point.lengthSqr();
    if (OCSquared < Sqr(BottomRadius))
    {
        INSide = true;
    }
    Other = New_Point - Origin;
    OCSquared = Other.lengthSqr();
    if (OCSquared < Sqr(TopRadius))
    {
        INSide = true;
    }
    vertical = New_Point[Y];
    if ((vertical > BottomVertical) && (vertical < TopVertical))
    {
        horizontal = sqrt(Sqr(New_Point[X]) + Sqr(New_Point[Z]));
        OCSquared = Sqr(horizontal + HorizontalPosition) + Sqr((vertical - VerticalPosition));
        if (OCSquared < Sqr(ConnectingRadius))
        {
            INSide = true;
        }
    }
    if (Test_Flag(this, INVERTED_FLAG))
    {
        return !INSide;
    }
    else
    {
        return INSide;
    }
}
Beispiel #9
0
void Torus::CalcUV(const VECTOR IPoint, UV_VECT Result) const
{
	DBL len, v, u, x, y, z;
	VECTOR P;

	// Transform the ray into the torus space.
	MInvTransPoint(P, IPoint, Trans);
	x = P[X];
	y = P[Y];
	z = P[Z];

	// Determine its angle from the y-axis.
	u = (1.0 - (atan2(z, x) + M_PI) / TWO_M_PI);

	len = sqrt(x * x + z * z);

	// Now rotate about the y-axis to get the point P into the x-z plane.
	x = len - MajorRadius;
	v = (atan2(y, x) + M_PI) / TWO_M_PI;

	Result[U] = u;
	Result[V] = v;
}
Beispiel #10
0
void Superellipsoid::Normal(Vector3d& Result, Intersection *Inter, TraceThreadData *Thread) const
{
    Vector3d const& E = Power;
    Vector3d P;

    /* Transform the point into the superellipsoid space. */
    MInvTransPoint(P, Inter->IPoint, Trans);

    DBL r, z2n = 0;
    if (P[Z] != 0)
    {
        z2n = power(fabs(P[Z]), E[Z]);
        P[Z] = z2n / P[Z];
    }

    if (fabs(P[X]) > fabs(P[Y]))
    {
        r = power(fabs(P[Y] / P[X]), E[X]);

        P[X] = (1-z2n)  /  P[X];
        P[Y] = P[Y] ? (1-z2n) * r / P[Y] : 0;
    }
    else if (P[Y] != 0)
    {
        r = power(fabs(P[X] / P[Y]), E[X]);

        P[X] = P[X] ? (1-z2n) * r / P[X] : 0;
        P[Y] = (1-z2n) / P[Y];
    }
    if(P[Z])
        P[Z] *= (1 + r);

    /* Transform the normalt out of the superellipsoid space. */
    MTransNormal(Result, P, Trans);

    Result.normalize();
}
Beispiel #11
0
static int Inside_Box(VECTOR IPoint, OBJECT *Object)
{
  VECTOR New_Point;
  BOX *box = (BOX *) Object;

  /* Transform the point into box space. */

  if (box->Trans != NULL)
  {
    MInvTransPoint(New_Point, IPoint, box->Trans);
  }
  else
  {
    Assign_Vector(New_Point,IPoint);
  }

  /* Test to see if we are outside the box. */

  if ((New_Point[X] < box->bounds[0][X]) || (New_Point[X] > box->bounds[1][X]))
  {
    return (Test_Flag(box, INVERTED_FLAG));
  }

  if ((New_Point[Y] < box->bounds[0][Y]) || (New_Point[Y] > box->bounds[1][Y]))
  {
    return (Test_Flag(box, INVERTED_FLAG));
  }

  if ((New_Point[Z] < box->bounds[0][Z]) || (New_Point[Z] > box->bounds[1][Z]))
  {
    return (Test_Flag(box, INVERTED_FLAG));
  }

  /* Inside the box. */

  return (!Test_Flag(box, INVERTED_FLAG));
}
Beispiel #12
0
bool SpindleTorus::Inside(const Vector3d& IPoint, TraceThreadData *Thread) const
{
    DBL r, r2;
    Vector3d P;
    bool inside;

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

    MInvTransPoint(P, IPoint, Trans);

    r  = sqrt(Sqr(P[X]) + Sqr(P[Z]));

    r2 = Sqr(P[Y]) + Sqr(r - MajorRadius);

    if (r2 <= Sqr(MinorRadius))
    {
        if (mSpindleMode & SpindleRelevantForInside)
        {
            bool insideSpindle = ( Sqr(P[Y]) + Sqr(r + MajorRadius) <= Sqr(MinorRadius) );
            if (mSpindleMode & SpindleInside)
                inside = insideSpindle;
            else
                inside = !insideSpindle;
        }
        else
            inside = true;

    }
    else
        inside = false;

    if (inside)
        return(!Test_Flag(this, INVERTED_FLAG));
    else
        return(Test_Flag(this, INVERTED_FLAG));
}
Beispiel #13
0
bool Disc::Intersect(const BasicRay& ray, DBL *Depth) const
{
    DBL t, u, v, r2, len;
    Vector3d P, D;

    /* Transform the point into the discs space */

    MInvTransPoint(P, ray.Origin, Trans);
    MInvTransDirection(D, ray.Direction, Trans);

    len = D.length();
    D /= len;

    if (fabs(D[Z]) > EPSILON)
    {
        t = -P[Z] / D[Z];

        if (t >= 0.0)
        {
            u = P[X] + t * D[X];
            v = P[Y] + t * D[Y];

            r2 = Sqr(u) + Sqr(v);

            if ((r2 >= iradius2) && (r2 <= oradius2))
            {
                *Depth = t / len;

                if ((*Depth > DEPTH_TOLERANCE) && (*Depth < MAX_DISTANCE))
                    return (true);
            }
        }
    }

    return (false);
}
static void do_skysphere(RAY *Ray, COLOUR Colour)
{
  int i;
  DBL att, trans;
  COLOUR Col, Col_Temp, Filter;
  VECTOR P;
  SKYSPHERE *Skysphere;

  /* Why are we here. */

  if (Frame.Skysphere == NULL)
  {
    return;
  }

  Make_Colour(Col, 0.0, 0.0, 0.0);

  if (((Skysphere = Frame.Skysphere) != NULL) && (Skysphere->Pigments != NULL))
  {
    Make_ColourA(Filter, 1.0, 1.0, 1.0, 1.0, 1.0);

    trans = 1.0;

    /* Transform point on unit sphere. */

    if (Skysphere->Trans != NULL)
    {
      MInvTransPoint(P, Ray->Direction, Skysphere->Trans);
    }
    else
    {
      Assign_Vector(P, Ray->Direction);
    }

    for (i = Skysphere->Count-1; i >= 0; i--)
    {
      /* Compute sky colour from colour map. */

      /* NK 1998 - added NULL as final parameter */
      Compute_Pigment(Col_Temp, Skysphere->Pigments[i], P, NULL);
      /* NK ---- */

      att = trans * (1.0 - Col_Temp[pFILTER] - Col_Temp[pTRANSM]);

      CRGBAddScaledEq(Col, att, Col_Temp);

      Filter[pRED]    *= Col_Temp[pRED];
      Filter[pGREEN]  *= Col_Temp[pGREEN];
      Filter[pBLUE]   *= Col_Temp[pBLUE];
      Filter[pFILTER] *= Col_Temp[pFILTER];
      Filter[pTRANSM] *= Col_Temp[pTRANSM];

      trans = fabs(Filter[pFILTER]) + fabs(Filter[pTRANSM]);
    }

    Colour[pRED]    = Col[pRED]    + Colour[pRED]   * (Filter[pRED]   * Filter[pFILTER] + Filter[pTRANSM]);
    Colour[pGREEN]  = Col[pGREEN]  + Colour[pGREEN] * (Filter[pGREEN] * Filter[pFILTER] + Filter[pTRANSM]);
    Colour[pBLUE]   = Col[pBLUE]   + Colour[pBLUE]  * (Filter[pBLUE]  * Filter[pFILTER] + Filter[pTRANSM]);
    Colour[pFILTER] = Colour[pFILTER] * Filter[pFILTER];
    Colour[pTRANSM] = Colour[pTRANSM] * Filter[pTRANSM];
  }
}
Beispiel #15
0
bool IsoSurface::All_Intersections(const Ray& ray, IStack& Depth_Stack, TraceThreadData *Thread)
{
    int Side1 = 0, Side2 = 0, itrace = 0;
    DBL Depth1 = 0.0, Depth2 = 0.0;
    BasicRay New_Ray;
    Vector3d IPoint;
    Vector3d Plocal, Dlocal;
    DBL tmax = 0.0, tmin = 0.0, tmp = 0.0;
    DBL maxg = max_gradient;
    int i = 0 ; /* count of intervals in stack - 1      */
    int IFound = false;
    int begin = 0, end = 0;
    bool in_shadow_test = false;
    Vector3d VTmp;

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

    if(container->Intersect(ray, Trans, Depth1, Depth2, Side1, Side2)) /* IsoSurface_Bound_Tests */
    {
        Thread->Stats()[Ray_IsoSurface_Bound_Tests_Succeeded]++;

        in_shadow_test = ray.IsShadowTestRay();

        if(Depth1 < 0.0)
            Depth1 = 0.0;

        if(Trans != NULL)
        {
            MInvTransPoint(Plocal, ray.Origin, Trans);
            MInvTransDirection(Dlocal, ray.Direction, Trans);
        }
        else
        {
            Plocal = ray.Origin;
            Dlocal = ray.Direction;
        }

        Thread->isosurfaceData->Inv3 = 1;

        if(closed != false)
        {
            VTmp = Plocal + Depth1 * Dlocal;
            tmp = Vector_Function(Thread->functionContext, VTmp);
            if(Depth1 > accuracy)
            {
                if(tmp < 0.0)                   /* The ray hits the bounding shape */
                {
                    IPoint = ray.Evaluate(Depth1);
                    if(Clip.empty() || Point_In_Clip(IPoint, Clip, Thread))
                    {
                        Depth_Stack->push(Intersection(Depth1, IPoint, this, 1, Side1));
                        IFound = true;
                        itrace++;
                        Thread->isosurfaceData->Inv3 *= -1;
                    }
                }
            }
            else
            {
                if(tmp < (maxg * accuracy * 4.0))
                {
                    Depth1 = accuracy * 5.0;
                    VTmp = Plocal + Depth1 * Dlocal;
                    if(Vector_Function(Thread->functionContext, VTmp) < 0)
                        Thread->isosurfaceData->Inv3 = -1;
                    /* Change the sign of the function (IPoint is in the bounding shpae.)*/
                }
                VTmp = Plocal + Depth2 * Dlocal;
                if(Vector_Function(Thread->functionContext, VTmp) < 0.0)
                {
                    IPoint = ray.Evaluate(Depth2);
                    if(Clip.empty() || Point_In_Clip(IPoint, Clip, Thread))
                    {
                        Depth_Stack->push(Intersection(Depth2, IPoint, this, 1, Side2));
                        IFound = true;
                    }
                }
            }
        }

        /*  METHOD 2   by R. Suzuki */
        tmax = Depth2 = min(Depth2, BOUND_HUGE);
        tmin = Depth1 = min(Depth2, Depth1);
        if((tmax - tmin) < accuracy)
        {
            if (IFound)
                Depth_Stack->pop(); // we added an intersection already, so we need to undo that
            return (false);
        }
        Thread->Stats()[Ray_IsoSurface_Tests]++;
        if((Depth1 < accuracy) && (Thread->isosurfaceData->Inv3 == 1))
        {
            /* IPoint is on the isosurface */
            VTmp = Plocal + tmin * Dlocal;
            if(fabs(Vector_Function(Thread->functionContext, VTmp)) < (maxg * accuracy * 4.0))
            {
                tmin = accuracy * 5.0;
                VTmp = Plocal + tmin * Dlocal;
                if(Vector_Function(Thread->functionContext, VTmp) < 0)
                    Thread->isosurfaceData->Inv3 = -1;
                /* change the sign and go into the isosurface */
            }
        }

        Thread->isosurfaceData->ctx = Thread->functionContext;

        for (; itrace < max_trace; itrace++)
        {
            if(Function_Find_Root(*(Thread->isosurfaceData), Plocal, Dlocal, &tmin, &tmax, maxg, in_shadow_test, Thread) == false)
                break;
            else
            {
                IPoint = ray.Evaluate(tmin);
                if(Clip.empty() || Point_In_Clip(IPoint, Clip, Thread))
                {
                    Depth_Stack->push(Intersection(tmin, IPoint, this, 0, 0 /*Side1*/));
                    IFound = true;
                }
            }
            tmin += accuracy * 5.0;
            if((tmax - tmin) < accuracy)
                break;
            Thread->isosurfaceData->Inv3 *= -1;
        }

        if(IFound)
            Thread->Stats()[Ray_IsoSurface_Tests_Succeeded]++;
    }

    if(eval == true)
    {
        DBL temp_max_gradient = max_gradient; // TODO FIXME - works around nasty gcc (found using 4.0.1) bug failing to honor casting away of volatile on pass by value on template argument lookup [trf]
        max_gradient = max((DBL)temp_max_gradient, maxg); // TODO FIXME - This is not thread-safe but should be!!! [trf]
    }

    return (IFound);
}
Beispiel #16
0
bool TransformWarp::WarpPoint(Vector3d& TPoint) const
{
    MInvTransPoint(TPoint, TPoint, &Trans);
    return true;
}
Beispiel #17
0
static int All_IsoSurface_Intersections(OBJECT* Object, RAY* Ray, ISTACK* Depth_Stack)
{
	ISOSURFACE * Isosrf = (ISOSURFACE *)Object;
	int Side1 = 0, Side2 = 0, itrace = 0, i_flg = 0;
	DBL Depth1 = 0.0, Depth2 = 0.0, len = 0.0;
	RAY New_Ray;
	VECTOR IPoint;
	VECTOR P, D;
	DBL tmax = 0.0, tmin = 0.0, tmp = 0.0;
	int i = 0 ; /* count of intervals in stack - 1      */
	int IFound = false;
	int begin = 0, end = 0;
	bool in_shadow_test = false;
	VECTOR VTmp;

	Increase_Counter(stats[Ray_IsoSurface_Bound_Tests]);

	in_shadow_test = ((Ray->Optimisiation_Flags & OPTIMISE_SHADOW_TEST) == OPTIMISE_SHADOW_TEST);

	if(Isosrf->container_shape)
	{
		if(Isosrf->Trans != NULL)
		{
			MInvTransPoint(New_Ray.Initial, Ray->Initial, Isosrf->Trans);
			MInvTransDirection(New_Ray.Direction, Ray->Direction, Isosrf->Trans);
			VLength(len, New_Ray.Direction);
			VInverseScaleEq(New_Ray.Direction, len);
			i_flg = Intersect_Sphere(&New_Ray, Isosrf->container.sphere.center, 
			                         (Isosrf->container.sphere.radius) * (Isosrf->container.sphere.radius),
			                         &Depth1, &Depth2);
			Depth1 = Depth1 / len;
			Depth2 = Depth2 / len;
		}
		else
		{
			i_flg = Intersect_Sphere(Ray, Isosrf->container.sphere.center, 
			                         (Isosrf->container.sphere.radius) * (Isosrf->container.sphere.radius), &Depth1, &Depth2);
		}
		Decrease_Counter(stats[Ray_Sphere_Tests]);
		if(i_flg)
			Decrease_Counter(stats[Ray_Sphere_Tests_Succeeded]);
	}
	else
	{
		i_flg = Intersect_Box(Ray, Isosrf->Trans, Isosrf->container.box.corner1, Isosrf->container.box.corner2,
		                      &Depth1, &Depth2, &Side1, &Side2);
	}

	if(Depth1 < 0.0)
		Depth1 = 0.0;

	if(i_flg)									/* IsoSurface_Bound_Tests */
	{
		Increase_Counter(stats[Ray_IsoSurface_Bound_Tests_Succeeded]);
		if(Isosrf->Trans != NULL)
		{
			MInvTransPoint(P, Ray->Initial, Isosrf->Trans);
			MInvTransDirection(D, Ray->Direction, Isosrf->Trans);
		}
		else
		{
			Assign_Vector(P, Ray->Initial);
			Assign_Vector(D, Ray->Direction);
		}
		Isosrf->Inv3 = 1;

		if(Isosrf->closed != false)
		{
			VEvaluateRay(VTmp, P, Depth1, D);
			tmp = Vector_IsoSurface_Function(Isosrf, VTmp);
			if(Depth1 > Isosrf->accuracy)
			{
				if(tmp < 0.0)					/* The ray hits the bounding shape */
				{
					VEvaluateRay(IPoint, Ray->Initial, Depth1, Ray->Direction);
					if(Point_In_Clip(IPoint, Object->Clip))
					{
						push_entry_i1(Depth1, IPoint, Object, Side1, Depth_Stack);
						IFound = true;
						itrace++;
						Isosrf->Inv3 *= -1;
					}
				}
			}
			else
			{
				if(tmp < (Isosrf->max_gradient * Isosrf->accuracy * 4.0))
				{
					Depth1 = Isosrf->accuracy * 5.0;
					VEvaluateRay(VTmp, P, Depth1, D);
					if(Vector_IsoSurface_Function(Isosrf, VTmp) < 0)
						Isosrf->Inv3 = -1;
					/* Change the sign of the function (IPoint is in the bounding shpae.)*/
				}
				VEvaluateRay(VTmp, P, Depth2, D);
				if(Vector_IsoSurface_Function(Isosrf, VTmp) < 0.0)
				{
					VEvaluateRay(IPoint, Ray->Initial, Depth2, Ray->Direction);
					if(Point_In_Clip(IPoint, Object->Clip))
					{
						push_entry_i1(Depth2, IPoint, Object, Side2, Depth_Stack);
						IFound = true;
					}
				}
			}
		}

		/*  METHOD 2   by R. Suzuki */
		tmax = Depth2 = min(Depth2, BOUND_HUGE);
		tmin = Depth1 = min(Depth2, Depth1);
		if((tmax - tmin) < Isosrf->accuracy)
			return (false);
		Increase_Counter(stats[Ray_IsoSurface_Tests]);
		if((Depth1 < Isosrf->accuracy) && (Isosrf->Inv3 == 1))
		{
			/* IPoint is on the isosurface */
			VEvaluateRay(VTmp, P, tmin, D);
			if(fabs(Vector_IsoSurface_Function(Isosrf, VTmp)) < (Isosrf->max_gradient * Isosrf->accuracy * 4.0))
			{
				tmin = Isosrf->accuracy * 5.0;
				VEvaluateRay(VTmp, P, tmin, D);
				if(Vector_IsoSurface_Function(Isosrf, VTmp) < 0)
					Isosrf->Inv3 = -1;
				/* change the sign and go into the isosurface */
			}
		}

		for (; itrace < Isosrf->max_trace; itrace++)
		{
			if(IsoSurface_Function_Find_Root(Isosrf, P, D, &tmin, &tmax, in_shadow_test) == false)
				break;
			else
			{
				VEvaluateRay(IPoint, Ray->Initial, tmin, Ray->Direction);
				if(Point_In_Clip(IPoint, Object->Clip))
				{
					push_entry_i1(tmin, IPoint, Object, 0 /*Side1*/, Depth_Stack);
					IFound = true;
				}
			}
			tmin += Isosrf->accuracy * 5.0;
			if((tmax - tmin) < Isosrf->accuracy)
				break;
			Isosrf->Inv3 *= -1;
		}

		if(IFound)
			Increase_Counter(stats[Ray_IsoSurface_Tests_Succeeded]);
	}

	return (IFound);
}
Beispiel #18
0
void Compute_Plane_Min_Max(PLANE *Plane, VECTOR Min, VECTOR  Max)
{
  DBL d;
  VECTOR P, N;

  if (Plane->Trans == NULL)
  {
    Assign_Vector(N, Plane->Normal_Vector);

    d = -Plane->Distance;
  }
  else
  {
    MInvTransNormal(N, Plane->Normal_Vector, Plane->Trans);

    MInvTransPoint(P, N, Plane->Trans);

    d = -Plane->Distance - P[X] * N[X] - P[Y] * N[Y] - P[Z] * N[Z] + 1.0;
  }

  Min[X] = Min[Y] = Min[Z] = -BOUND_HUGE/2;
  Max[X] = Max[Y] = Max[Z] =  BOUND_HUGE/2;

  /* y-z-plane */

  if (fabs(1.0 - fabs(N[X])) < EPSILON)
  {
    if (N[X] > 0.0)
    {
      Max[X] = d;
    }
    else
    {
      Min[X] = -d;
    }
  }

  /* x-z-plane */

  if (fabs(1.0 - fabs(N[Y])) < EPSILON)
  {
    if (N[Y] > 0.0)
    {
      Max[Y] = d;
    }
    else
    {
      Min[Y] = -d;
    }
  }

  /* x-y-plane */

  if (fabs(1.0 - fabs(N[Z])) < EPSILON)
  {
    if (N[Z] > 0.0)
    {
      Max[Z] = d;
    }
    else
    {
      Min[Z] = -d;
    }
  }
}
Beispiel #19
0
bool Ovus::All_Intersections(const Ray& ray, IStack& Depth_Stack, TraceThreadData *Thread)
{
    bool Found = false;
    Vector3d Real_Normal, Real_Pt, INormal, IPoint;
    DBL Depth1, Depth2, Depth3, Depth4, Depth5, Depth6;
    DBL len, horizontal;
    Vector3d P,D;

    Thread->Stats()[Ray_Ovus_Tests]++;
    MInvTransPoint(P, ray.Origin, Trans);
    MInvTransDirection(D, ray.Direction, Trans);
    len = D.length();
    D /= len;

    Intersect_Ovus_Spheres(P, D, &Depth1, &Depth2, &Depth3,
                           &Depth4, &Depth5, &Depth6, Thread);
    if (Depth1 > EPSILON)
    {
        IPoint = P + Depth1 * D;
        if (IPoint[Y] < BottomVertical)
        {
            MTransPoint(Real_Pt, IPoint, Trans);
            if (Clip.empty()||(Point_In_Clip(Real_Pt, Clip, Thread)))
            {
                INormal = IPoint / BottomRadius;
                MTransNormal(Real_Normal, INormal, Trans);
                Real_Normal.normalize();
                Depth_Stack->push(Intersection(Depth1/len, Real_Pt, Real_Normal, this));
                Found = true;
            }
        }
    }

    if (Depth2 > EPSILON)
    {
        IPoint = P + Depth2 * D;

        if (IPoint[Y] < BottomVertical)
        {
            MTransPoint(Real_Pt, IPoint, Trans);
            if (Clip.empty()||(Point_In_Clip(Real_Pt, Clip, Thread)))
            {
                INormal = IPoint / BottomRadius;
                MTransNormal(Real_Normal, INormal, Trans);
                Real_Normal.normalize();
                Depth_Stack->push(Intersection(Depth2/len, Real_Pt, Real_Normal, this));
                Found = true;
            }
        }
    }

    if (Depth3 > EPSILON)
    {
        IPoint = P + Depth3 * D;

        if (IPoint[Y] > TopVertical)
        {
            MTransPoint(Real_Pt, IPoint, Trans);
            if (Clip.empty()||(Point_In_Clip(Real_Pt, Clip, Thread)))
            {
                INormal = IPoint;
                INormal[Y] -= BottomRadius;
                INormal /= TopRadius;
                MTransNormal(Real_Normal, INormal, Trans);
                Real_Normal.normalize();
                Depth_Stack->push(Intersection(Depth3/len, Real_Pt, Real_Normal, this));
                Found = true;
            }
        }
    }
    if (Depth4 > EPSILON)
    {
        IPoint = P + Depth4 * D;

        if (IPoint[Y] > TopVertical)
        {
            MTransPoint(Real_Pt, IPoint, Trans);
            if (Clip.empty()||(Point_In_Clip(Real_Pt, Clip, Thread)))
            {
                INormal = IPoint;
                INormal[Y] -= BottomRadius;
                INormal /= TopRadius;
                MTransNormal(Real_Normal, INormal, Trans);
                Real_Normal.normalize();
                Depth_Stack->push(Intersection(Depth4/len, Real_Pt, Real_Normal, this));
                Found = true;
            }
        }
    }

    if (Depth5 > EPSILON)
    {
        IPoint = P + Depth5 * D;
        MTransPoint(Real_Pt, IPoint, Trans);

        if (Clip.empty()||(Point_In_Clip(Real_Pt, Clip, Thread)))
        {
            INormal = IPoint;

            INormal[Y] -= VerticalPosition;
            horizontal = sqrt(Sqr(INormal[X]) + Sqr(INormal[Z]));
            INormal[X] += (INormal[X] * HorizontalPosition / horizontal);
            INormal[Z] += (INormal[Z] * HorizontalPosition / horizontal);
            INormal.normalize();
            MTransNormal(Real_Normal, INormal, Trans);
            Real_Normal.normalize();
            Depth_Stack->push(Intersection(Depth5/len, Real_Pt, Real_Normal, this));
            Found = true;
        }
    }
    if (Depth6 > EPSILON)
    {
        IPoint = P + Depth6 * D;
        MTransPoint(Real_Pt, IPoint, Trans);

        if (Clip.empty()||(Point_In_Clip(Real_Pt, Clip, Thread)))
        {
            INormal = IPoint;
            INormal[Y] -= VerticalPosition;
            horizontal = sqrt(Sqr(INormal[X]) + Sqr(INormal[Z]));
            INormal[X] += (INormal[X] * HorizontalPosition / horizontal);
            INormal[Z] += (INormal[Z] * HorizontalPosition / horizontal);
            INormal.normalize();
            MTransNormal(Real_Normal, INormal, Trans);
            Real_Normal.normalize();

            Depth_Stack->push(Intersection(Depth6/len, Real_Pt, Real_Normal, this));
            Found = true;
        }
    }
    if (Found)
    {
        Thread->Stats()[Ray_Ovus_Tests_Succeeded]++;
    }
    return (Found);
}
Beispiel #20
0
void Ovus::CalcUV(const Vector3d& IPoint, Vector2d& Result) const
{
    DBL len, x, y, z;
    DBL phi, theta;
    Vector3d P;

    // Transform the ray into the ovus space.
    MInvTransPoint(P, IPoint, Trans);

    // the center of UV coordinate is the bottom center when top radius ->0
    // and it is the top center when top radius -> 2.0* bottom radius
    // when top radius == bottom radius, it is half-way between both center
    //
    // bottom center is <0,0,0>
    // top center is <0,BottomRadius,0>
    // TODO FIXME - comment doesn't seem to match the following code
    x = P[X];
//  y = P[Y] - BottomRadius*(TopRadius/(2.0*BottomRadius));
    y = P[Y] - (TopRadius/2.0);
    z = P[Z];

    // now assume it's just a sphere, for UV mapping/projection
    len = sqrt(x * x + y * y + z * z);

    if (len == 0.0)
        return;
    else
    {
        x /= len;
        y /= len;
        z /= len;
    }

    // Determine its angle from the x-z plane.
    phi = 0.5 + asin(y) / M_PI; // This will be from 0 to 1

    // Determine its angle from the point (1, 0, 0) in the x-z plane.
    len = x * x + z * z;

    if (len > EPSILON)
    {
        len = sqrt(len);
        if (z == 0.0)
        {
            if (x > 0)
                theta = 0.0;
            else
                theta = M_PI;
        }
        else
        {
            theta = acos(x / len);
            if (z < 0.0)
                theta = TWO_M_PI - theta;
        }

        theta /= TWO_M_PI; // This will be from 0 to 1
    }
    else
        // This point is at one of the poles. Any value of xcoord will be ok...
        theta = 0;

    Result[U] = theta;
    Result[V] = phi;

}
Beispiel #21
0
bool Parametric::All_Intersections(const Ray& ray, IStack& Depth_Stack, TraceThreadData *Thread)
{
	VECTOR P, D, IPoint;
	UV_VECT low_vect, hi_vect, uv;
	Ray New_Ray;
	DBL XRayMin, XRayMax, YRayMin, YRayMax, ZRayMin, ZRayMax, TPotRes, TLen;
	DBL Depth1, Depth2, temp, Len, TResult = HUGE_VAL;
	DBL low, hi, len;
	int MaxPrecompX, MaxPrecompY, MaxPrecompZ;
	int split, i = 0, Side1, Side2;
	int parX, parY;
	int i_flg;
	DBL Intervals_Low[2][32];
	DBL Intervals_Hi[2][32];
	int SectorNum[32];

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

	if(container_shape)
	{
		if(Trans != NULL)
		{
			MInvTransPoint(New_Ray.Origin, ray.Origin, Trans);
			MInvTransDirection(New_Ray.Direction, ray.Direction, Trans);
			VLength(len, New_Ray.Direction);
			VInverseScaleEq(New_Ray.Direction, len);
			i_flg = Sphere::Intersect(New_Ray, container.sphere.center,
			                          (container.sphere.radius) * (container.sphere.radius),
			                          &Depth1, &Depth2);
			Depth1 = Depth1 / len;
			Depth2 = Depth2 / len;
		}
		else
		{
			i_flg = Sphere::Intersect(ray, container.sphere.center,
			                          (container.sphere.radius) * (container.sphere.radius), &Depth1, &Depth2);
		}
		Thread->Stats()[Ray_Sphere_Tests]--;
		if(i_flg)
			Thread->Stats()[Ray_Sphere_Tests_Succeeded]--;
	}
	else
	{
		i_flg = Box::Intersect(ray, Trans, container.box.corner1, container.box.corner2,
		                       &Depth1, &Depth2, &Side1, &Side2);
	}

	if(!i_flg)
		return false;

	Thread->Stats()[Ray_Par_Bound_Tests_Succeeded]++;
	Thread->Stats()[Ray_Parametric_Tests]++;

	if (Trans != NULL)
	{
		MInvTransPoint(P, ray.Origin, Trans);
		MInvTransDirection(D, ray.Direction, Trans);
	}
	else
	{
		P[X] = ray.Origin[X];
		P[Y] = ray.Origin[Y];
		P[Z] = ray.Origin[Z];
		D[X] = ray.Direction[X];
		D[Y] = ray.Direction[Y];
		D[Z] = ray.Direction[Z];
	}

	if (Depth1 == Depth2)
		Depth1 = 0;

	if ((Depth1 += 4 * accuracy) > Depth2)
		return false;

	Intervals_Low[INDEX_U][0] = umin;
	Intervals_Hi[INDEX_U][0] = umax;

	Intervals_Low[INDEX_V][0] = vmin;
	Intervals_Hi[INDEX_V][0] = vmax;
	/* Fri 09-27-1996 0. */
	SectorNum[0] = 1;

	MaxPrecompX = MaxPrecompY = MaxPrecompZ = 0;
	if (PData != NULL)
	{
		if (((PData->flags) & OK_X) != 0)
			MaxPrecompX = 1 << (PData->depth);
		if (((PData->flags) & OK_Y) != 0)
			MaxPrecompY = 1 << (PData->depth);
		if (((PData->flags) & OK_Z) != 0)
			MaxPrecompZ = 1 << (PData->depth);
	}
	/* 0 */
	while (i >= 0)
	{
		low_vect[U] = Intervals_Low[INDEX_U][i];
		hi_vect[U] = Intervals_Hi[INDEX_U][i];
		Len = hi_vect[U] - low_vect[U];
		split = INDEX_U;

		low_vect[V] = Intervals_Low[INDEX_V][i];
		hi_vect[V] = Intervals_Hi[INDEX_V][i];
		temp = hi_vect[V] - low_vect[V];
		if (temp > Len)
		{
			Len = temp;
			split = INDEX_V;
		}
		parX = parY = 0;
		TLen = 0;

		/* X */
		if (SectorNum[i] < MaxPrecompX)
		{
			low = PData->Low[0][SectorNum[i]];
			hi = PData->Hi[0][SectorNum[i]];
		}
		else
			Evaluate_Function_Interval_UV(Thread->functionContext, *(Function[0]), accuracy, low_vect, hi_vect, max_gradient, low, hi);
		/* fabs(D[X] *(T2-T1)) is not OK with new method */

		if (close(D[0], 0))
		{
			parX = 1;
			if ((hi < P[0]) || (low > P[0]))
			{
				i--;
				continue;
			}
		}
		else
		{
			XRayMin = (hi - P[0]) / D[0];
			XRayMax = (low - P[0]) / D[0];
			if (XRayMin > XRayMax)
			{
				temp = XRayMin;
				XRayMin = XRayMax;
				XRayMax = temp;
			}

			if ((XRayMin > Depth2) || (XRayMax < Depth1))
			{
				i--;
				continue;
			}

			if ((TPotRes = XRayMin) > TResult)
			{
				i--;
				continue;
			}

			TLen = XRayMax - XRayMin;
		}

		/* Y */
		if (SectorNum[i] < MaxPrecompY)
		{
			low = PData->Low[1][SectorNum[i]];
			hi = PData->Hi[1][SectorNum[i]];
		}
		else
			Evaluate_Function_Interval_UV(Thread->functionContext, *(Function[1]), accuracy, low_vect, hi_vect, max_gradient, low, hi);

		if (close(D[1], 0))
		{
			parY = 1;
			if ((hi < P[1]) || (low > P[1]))
			{
				i--;
				continue;
			}
		}
		else
		{
			YRayMin = (hi - P[1]) / D[1];
			YRayMax = (low - P[1]) / D[1];
			if (YRayMin > YRayMax)
			{
				temp = YRayMin;
				YRayMin = YRayMax;
				YRayMax = temp;
			}
			if ((YRayMin > Depth2) || (YRayMax < Depth1))
			{
				i--;
				continue;
			}
			if ((TPotRes = YRayMin) > TResult)
			{
				i--;
				continue;
			}
			if (parX == 0)
			{
				if ((YRayMin > XRayMax) || (YRayMax < XRayMin))
				{
					i--;
					continue;
				}
			}
			if ((temp = YRayMax - YRayMin) > TLen)
				TLen = temp;
		}

		/* Z */
		if ((SectorNum[i] < MaxPrecompZ) && (0 < SectorNum[i]))
		{
			low = PData->Low[2][SectorNum[i]];
			hi = PData->Hi[2][SectorNum[i]];
		}
		else
			Evaluate_Function_Interval_UV(Thread->functionContext, *(Function[2]), accuracy, low_vect, hi_vect, max_gradient, low, hi);

		if (close(D[2], 0))
		{
			if ((hi < P[2]) || (low > P[2]))
			{
				i--;
				continue;
			}
		}
		else
		{
			ZRayMin = (hi - P[2]) / D[2];
			ZRayMax = (low - P[2]) / D[2];
			if (ZRayMin > ZRayMax)
			{
				temp = ZRayMin;
				ZRayMin = ZRayMax;
				ZRayMax = temp;
			}
			if ((ZRayMin > Depth2) || (ZRayMax < Depth1))
			{
				i--;
				continue;
			}
			if ((TPotRes = ZRayMin) > TResult)
			{
				i--;
				continue;
			}
			if (parX == 0)
			{
				if ((ZRayMin > XRayMax) || (ZRayMax < XRayMin))
				{
					i--;
					continue;
				}
			}
			if (parY == 0)
			{
				if ((ZRayMin > YRayMax) || (ZRayMax < YRayMin))
				{
					i--;
					continue;
				}
			}
			if ((temp = ZRayMax - ZRayMin) > TLen)
				TLen = temp;
		}

		if (Len > TLen)
			Len = TLen;
		if (Len < accuracy)
		{
			if ((TResult > TPotRes) && (TPotRes > Depth1))
			{
				TResult = TPotRes;
				Assign_UV_Vect(uv, low_vect);
			}
			i--;
		}
		else
		{
			/* 1 copy */
			if ((SectorNum[i] *= 2) >= Max_intNumber)
				SectorNum[i] = Max_intNumber;
			SectorNum[i + 1] = SectorNum[i];
			SectorNum[i]++;
			i++;
			Intervals_Low[INDEX_U][i] = low_vect[U];
			Intervals_Hi[INDEX_U][i] = hi_vect[U];

			Intervals_Low[INDEX_V][i] = low_vect[V];
			Intervals_Hi[INDEX_V][i] = hi_vect[V];

			/* 2 split */
			temp = (Intervals_Hi[split][i] + Intervals_Low[split][i]) / 2.0;
			Intervals_Hi[split][i] = temp;
			Intervals_Low[split][i - 1] = temp;
		}
	}

	if (TResult < Depth2)
	{
		Thread->Stats()[Ray_Parametric_Tests_Succeeded]++;
		VScale(IPoint, ray.Direction, TResult);
		VAddEq(IPoint, ray.Origin);

		if (Clip.empty() || Point_In_Clip(IPoint, Clip, Thread))
		{
			/*
			  compute_param_normal( Par, UResult, VResult , &N); 
			  push_normal_entry( TResult ,IPoint, N, (ObjectPtr ) Object, Depth_Stack);
			*/
			Depth_Stack->push(Intersection(TResult, IPoint, uv, this));

			return true;
		}
	}

	return false;
}
Beispiel #22
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);
}
Beispiel #23
0
static void Box_UVCoord(UV_VECT Result, OBJECT *Object, INTERSECTION *Inter)
{
  VECTOR P, Box_Diff;
  BOX *Box = (BOX *)Object;

  /* Transform the point into the cube's space */
  if (Box->Trans != NULL)
    MInvTransPoint(P, Inter->IPoint, Box->Trans);
  else
    Assign_Vector(P, Inter->IPoint);

  VSub(Box_Diff,Box->bounds[1],Box->bounds[0]);

  /* this line moves the bottom,left,front corner of the box to <0,0,0> */
  VSubEq(P, Box->bounds[0]);
  /* this line normalizes the face offsets */
  VDivEq(P, Box_Diff);

  /* if no normalize above, then we should use Box->UV_Trans and also
     inverse-transform the bounds */

  /* The following code does a variation of cube environment mapping. All the
     textures are not mirrored when the cube is viewed from outside. */

  switch (Inter->i1)
  {
    case SIDE_X_0:
      Result[U] =               (P[Z] / 4.0);
      Result[V] = (1.0 / 3.0) + (P[Y] / 3.0);
      break;
    case SIDE_X_1:
      Result[U] = (3.0 / 4.0) - (P[Z] / 4.0);
      Result[V] = (1.0 / 3.0) + (P[Y] / 3.0);
      break;
    case SIDE_Y_0:
      Result[U] = (1.0 / 4.0) + (P[X] / 4.0);
      Result[V] =               (P[Z] / 3.0);
      break;
    case SIDE_Y_1:
      Result[U] = (1.0 / 4.0) + (P[X] / 4.0);
      Result[V] = (3.0 / 3.0) - (P[Z] / 3.0);
      break;
    case SIDE_Z_0:
      Result[U] =  1.0        - (P[X] / 4.0);
      Result[V] = (1.0 / 3.0) + (P[Y] / 3.0);
      break;
    case SIDE_Z_1:
      Result[U] = (1.0 / 4.0) + (P[X] / 4.0);
      Result[V] = (1.0 / 3.0) + (P[Y] / 3.0);
      break;

    default: Error("Unknown box side in Box_Normal().");
  }

/* 
   This is the original cube environment mapping. The texture is correct
   when viewed from inside the cube. 

  switch (Inter->i1)
  {
  case SIDE_X_0:
	  Result[U] = (1.0 / 4.0) - (P[Z] / 4.0);
	  Result[V] = (1.0 / 3.0) + (P[Y] / 3.0);
	  break;
  case SIDE_X_1:
	  Result[U] = (2.0 / 4.0) + (P[Z] / 4.0);
	  Result[V] = (1.0 / 3.0) + (P[Y] / 3.0);
	  break;
  case SIDE_Y_0:
	  Result[U] = (1.0 / 4.0) + (P[X] / 4.0);
	  Result[V] = (1.0 / 3.0) - (P[Z] / 3.0);
	  break;
  case SIDE_Y_1:
	  Result[U] = (1.0 / 4.0) + (P[X] / 4.0);
	  Result[V] = (2.0 / 3.0) + (P[Z] / 3.0);
	  break;
  case SIDE_Z_0:
	  Result[U] = (1.0 / 4.0) + (P[X] / 4.0);
	  Result[V] = (1.0 / 3.0) + (P[Y] / 3.0);
	  break;
  case SIDE_Z_1:
	  Result[U] = 1.0         - (P[X] / 4.0);
	  Result[V] = (1.0 / 3.0) + (P[Y] / 3.0);
	  break;
	  
  default: Error("Unknown box side in Box_Normal().");
  }
  */
}
Beispiel #24
0
int Intersect_Box(RAY *Ray, TRANSFORM *Trans, VECTOR Corner1, VECTOR Corner2, DBL *Depth1, DBL  *Depth2, int *Side1, int  *Side2)
{
  int smin = 0, smax = 0;    /* Side hit for min/max intersection. */
  DBL t, tmin, tmax;
  VECTOR P, D;

  /* Transform the point into the boxes space */

  if (Trans != NULL)
  {
    MInvTransPoint(P, Ray->Initial, Trans);
    MInvTransDirection(D, Ray->Direction, Trans);
  }
  else
  {
    Assign_Vector(P, Ray->Initial);
    Assign_Vector(D, Ray->Direction);
  }

  tmin = 0.0;
  tmax = BOUND_HUGE;

  /*
   * Sides first.
   */

  if (D[X] < -EPSILON)
  {
    t = (Corner1[X] - P[X]) / D[X];

    if (t < tmin) return(false);

    if (t <= tmax)
    {
      smax = SIDE_X_0;
      tmax = t;
    }

    t = (Corner2[X] - P[X]) / D[X];

    if (t >= tmin)
    {
      if (t > tmax) return(false);

      smin = SIDE_X_1;
      tmin = t;
    }
  }
  else
  {
    if (D[X] > EPSILON)
    {
      t = (Corner2[X] - P[X]) / D[X];

      if (t < tmin) return(false);

      if (t <= tmax)
      {
        smax = SIDE_X_1;
        tmax = t;
      }

      t = (Corner1[X] - P[X]) / D[X];

      if (t >= tmin)
      {
        if (t > tmax) return(false);

        smin = SIDE_X_0;
        tmin = t;
      }
    }
    else
    {
      if ((P[X] < Corner1[X]) || (P[X] > Corner2[X]))
      {
        return(false);
      }
    }
  }

  /*
   * Check Top/Bottom.
   */

  if (D[Y] < -EPSILON)
  {
    t = (Corner1[Y] - P[Y]) / D[Y];

    if (t < tmin) return(false);

    if (t <= tmax - CLOSE_TOLERANCE)
    {
      smax = SIDE_Y_0;
      tmax = t;
    }
    else
    {
      /*
       * If intersection points are close to each other find out
       * which side to use, i.e. is most probably hit. [DB 9/94]
       */

      if (t <= tmax + CLOSE_TOLERANCE)
      {
        if (-D[Y] > fabs(D[X])) smax = SIDE_Y_0;
      }
    }

    t = (Corner2[Y] - P[Y]) / D[Y];

    if (t >= tmin + CLOSE_TOLERANCE)
    {
      if (t > tmax) return(false);

      smin = SIDE_Y_1;
      tmin = t;
    }
    else
    {
      /*
       * If intersection points are close to each other find out
       * which side to use, i.e. is most probably hit. [DB 9/94]
       */

      if (t >= tmin - CLOSE_TOLERANCE)
      {
        if (-D[Y] > fabs(D[X])) smin = SIDE_Y_1;
      }
    }
  }
  else
  {
    if (D[Y] > EPSILON)
    {
      t = (Corner2[Y] - P[Y]) / D[Y];

      if (t < tmin) return(false);

      if (t <= tmax - CLOSE_TOLERANCE)
      {
        smax = SIDE_Y_1;
        tmax = t;
      }
      else
      {
        /*
         * If intersection points are close to each other find out
         * which side to use, i.e. is most probably hit. [DB 9/94]
         */

        if (t <= tmax + CLOSE_TOLERANCE)
        {
          if (D[Y] > fabs(D[X])) smax = SIDE_Y_1;
        }
      }

      t = (Corner1[Y] - P[Y]) / D[Y];

      if (t >= tmin + CLOSE_TOLERANCE)
      {
        if (t > tmax) return(false);

        smin = SIDE_Y_0;
        tmin = t;
      }
      else
      {
        /*
         * If intersection points are close to each other find out
         * which side to use, i.e. is most probably hit. [DB 9/94]
         */

        if (t >= tmin - CLOSE_TOLERANCE)
        {
          if (D[Y] > fabs(D[X])) smin = SIDE_Y_0;
        }
      }
    }
    else
    {
      if ((P[Y] < Corner1[Y]) || (P[Y] > Corner2[Y]))
      {
        return(false);
      }
    }
  }

  /* Now front/back */

  if (D[Z] < -EPSILON)
  {
    t = (Corner1[Z] - P[Z]) / D[Z];

    if (t < tmin) return(false);

    if (t <= tmax - CLOSE_TOLERANCE)
    {
      smax = SIDE_Z_0;
      tmax = t;
    }
    else
    {
      /*
       * If intersection points are close to each other find out
       * which side to use, i.e. is most probably hit. [DB 9/94]
       */

      if (t <= tmax + CLOSE_TOLERANCE)
      {
        switch (smax)
        {
          case SIDE_X_0 :
          case SIDE_X_1 : if (-D[Z] > fabs(D[X])) smax = SIDE_Z_0; break;

          case SIDE_Y_0 :
          case SIDE_Y_1 : if (-D[Z] > fabs(D[Y])) smax = SIDE_Z_0; break;
        }
      }
    }

    t = (Corner2[Z] - P[Z]) / D[Z];

    if (t >= tmin + CLOSE_TOLERANCE)
    {
      if (t > tmax) return(false);

      smin = SIDE_Z_1;
      tmin = t;
    }
    else
    {
      /*
       * If intersection points are close to each other find out
       * which side to use, i.e. is most probably hit. [DB 9/94]
       */

      if (t >= tmin - CLOSE_TOLERANCE)
      {
        switch (smin)
        {
          case SIDE_X_0 :
          case SIDE_X_1 : if (-D[Z] > fabs(D[X])) smin = SIDE_Z_1; break;

          case SIDE_Y_0 :
          case SIDE_Y_1 : if (-D[Z] > fabs(D[Y])) smin = SIDE_Z_1; break;
        }
      }
    }
  }
  else
  {
    if (D[Z] > EPSILON)
    {
      t = (Corner2[Z] - P[Z]) / D[Z];

      if (t < tmin) return(false);

      if (t <= tmax - CLOSE_TOLERANCE)
      {
        smax = SIDE_Z_1;
        tmax = t;
      }
      else
      {
        /*
         * If intersection points are close to each other find out
         * which side to use, i.e. is most probably hit. [DB 9/94]
         */

        if (t <= tmax + CLOSE_TOLERANCE)
        {
          switch (smax)
          {
            case SIDE_X_0 :
            case SIDE_X_1 : if (D[Z] > fabs(D[X])) smax = SIDE_Z_1; break;

            case SIDE_Y_0 :
            case SIDE_Y_1 : if (D[Z] > fabs(D[Y])) smax = SIDE_Z_1; break;
          }
        }
      }

      t = (Corner1[Z] - P[Z]) / D[Z];

      if (t >= tmin + CLOSE_TOLERANCE)
      {
        if (t > tmax) return(false);

        smin = SIDE_Z_0;
        tmin = t;
      }
      else
      {
        /*
         * If intersection points are close to each other find out
         * which side to use, i.e. is most probably hit. [DB 9/94]
         */

        if (t >= tmin - CLOSE_TOLERANCE)
        {
          switch (smin)
          {
            case SIDE_X_0 :
            case SIDE_X_1 : if (D[Z] > fabs(D[X])) smin = SIDE_Z_0; break;

            case SIDE_Y_0 :
            case SIDE_Y_1 : if (D[Z] > fabs(D[Y])) smin = SIDE_Z_0; break;
          }
        }
      }
    }
    else
    {
      if ((P[Z] < Corner1[Z]) || (P[Z] > Corner2[Z]))
      {
        return(false);
      }
    }
  }

  if (tmax < DEPTH_TOLERANCE)
  {
    return (false);
  }

  *Depth1 = tmin;
  *Depth2 = tmax;

  *Side1 = smin;
  *Side2 = smax;

  return(true);
}
Beispiel #25
0
void Lemon::CalcUV(const Vector3d& IPoint, Vector2d& Result) const
{
    DBL len, x, y, z;
    DBL phi, theta;
    Vector3d P;

    // Transform the ray into the lemon space.
    MInvTransPoint(P, IPoint, Trans);

    // the center of UV coordinate is <0, 0, 1/2>
    // No fancy translation of the center as the radii are changed
    x = P[X];
    y = P[Y];
    z = P[Z]-0.5;

    // Determine its angle from the point (1, 0, 0) in the x-y plane.
    len = x * x + y * y;

    if ((P[Z]>EPSILON)&&(P[Z]<(1.0-EPSILON)))
    {
    // when not on a face, the range 0.25 to 0.75 is used (just plain magic 25% for face, no other reason, but it makes C-Lipka happy)
        phi = 0.25+0.5*P[Z];
    }
    else if (P[Z]>EPSILON)
    {
    // aka P[Z] is 1, use the apex_radius, from 75% to 100% (at the very center)
        phi = 1.0;
        if (apex_radius)
        {
            phi = 1.0-(sqrt(len)/(apex_radius*4));
        }
    }
    else
    {
    // aka P[Z] is 0, use the base_radius, from 0% (at the very center) to 25%
       phi = 0;
       if (base_radius)
       {
           phi = sqrt(len)/(base_radius*4);
       }
    }


    if (len > EPSILON)
    {
        len = sqrt(len);
        if (y == 0.0)
        {
            if (x > 0)
                theta = 0.0;
            else
                theta = M_PI;
        }
        else
        {
            theta = acos(x / len);
            if (y < 0.0)
                theta = TWO_M_PI - theta;
        }

        theta /= TWO_M_PI; // This will be from 0 to 1
    }
    else
        // This point is at one of the poles. Any value of xcoord will be ok...
        theta = 0;

    Result[U] = theta;
    Result[V] = phi;

}
Beispiel #26
0
int All_Parametric_Intersections(OBJECT* Object, RAY* Ray, ISTACK* Depth_Stack)
{
	PARAMETRIC * Par = (PARAMETRIC *)Object;
	PRECOMP_PAR_DATA * PData = ((PARAMETRIC *)Object)->PData;
	VECTOR P, D, IPoint;
	UV_VECT low_vect, hi_vect;
	RAY New_Ray;
	DBL XRayMin, XRayMax, YRayMin, YRayMax, ZRayMin, ZRayMax, TPotRes, TLen;
	DBL Depth1, Depth2, temp, Len, UResult, VResult, TResult = HUGE_VAL;
	DBL low, hi, len;
	int MaxPrecompX, MaxPrecompY, MaxPrecompZ;
	int split, i = 0, Side1, Side2;
	int parX, parY;
	int i_flg;

	Increase_Counter(stats[Ray_Par_Bound_Tests]);

	if(Par->container_shape)
	{
		if(Par->Trans != NULL)
		{
			MInvTransPoint(New_Ray.Initial, Ray->Initial, Par->Trans);
			MInvTransDirection(New_Ray.Direction, Ray->Direction, Par->Trans);
			VLength(len, New_Ray.Direction);
			VInverseScaleEq(New_Ray.Direction, len);
			i_flg = Intersect_Sphere(&New_Ray, Par->container.sphere.center, 
			                         (Par->container.sphere.radius) * (Par->container.sphere.radius),
			                         &Depth1, &Depth2);
			Depth1 = Depth1 / len;
			Depth2 = Depth2 / len;
		}
		else
		{
			i_flg = Intersect_Sphere(Ray, Par->container.sphere.center, 
			                         (Par->container.sphere.radius) * (Par->container.sphere.radius), &Depth1, &Depth2);
		}
		Decrease_Counter(stats[Ray_Sphere_Tests]);
		if(i_flg)
			Decrease_Counter(stats[Ray_Sphere_Tests_Succeeded]);
	}
	else
	{
		i_flg = Intersect_Box(Ray, Par->Trans, Par->container.box.corner1, Par->container.box.corner2,
		                      &Depth1, &Depth2, &Side1, &Side2);
	}

	if(!i_flg)
		return false;

	Increase_Counter(stats[Ray_Par_Bound_Tests_Succeeded]);
	Increase_Counter(stats[Ray_Parametric_Tests]);

	if (Par->Trans != NULL)
	{
		MInvTransPoint(P, Ray->Initial, Par->Trans);
		MInvTransDirection(D, Ray->Direction, Par->Trans);
	}
	else
	{
		P[X] = Ray->Initial[X];
		P[Y] = Ray->Initial[Y];
		P[Z] = Ray->Initial[Z];
		D[X] = Ray->Direction[X];
		D[Y] = Ray->Direction[Y];
		D[Z] = Ray->Direction[Z];
	}

	if (Depth1 == Depth2)
		Depth1 = 0;

	if ((Depth1 += 4 * Par->accuracy) > Depth2)
		return false;

	Intervals_Low[INDEX_U][0] = Par->umin;
	Intervals_Hi[INDEX_U][0] = Par->umax;

	Intervals_Low[INDEX_V][0] = Par->vmin;
	Intervals_Hi[INDEX_V][0] = Par->vmax;
	/* Fri 09-27-1996 0. */
	SectorNum[0] = 1;

	MaxPrecompX = MaxPrecompY = MaxPrecompZ = 0;
	if (PData != NULL)
	{
		if (((PData->flags) & OK_X) != 0)
			MaxPrecompX = 1 << (PData->depth);
		if (((PData->flags) & OK_Y) != 0)
			MaxPrecompY = 1 << (PData->depth);
		if (((PData->flags) & OK_Z) != 0)
			MaxPrecompZ = 1 << (PData->depth);
	}
	/* 0 */
	while (i >= 0)
	{
		low_vect[U] = Intervals_Low[INDEX_U][i];
		hi_vect[U] = Intervals_Hi[INDEX_U][i];
		Len = hi_vect[U] - low_vect[U];
		split = INDEX_U;

		low_vect[V] = Intervals_Low[INDEX_V][i];
		hi_vect[V] = Intervals_Hi[INDEX_V][i];
		temp = hi_vect[V] - low_vect[V];
		if (temp > Len)
		{
			Len = temp;
			split = INDEX_V;
		}
		parX = parY = 0;
		TLen = 0;

		/* X */
		if (SectorNum[i] < MaxPrecompX)
		{
			low = PData->Low[0][SectorNum[i]];
			hi = PData->Hi[0][SectorNum[i]];
		}
		else
			Evaluate_Function_Interval_UV(*(Par->Function[0]), Par->accuracy, low_vect, hi_vect, Par->max_gradient, low, hi);
		/* fabs(D[X] *(T2-T1)) is not OK with new method */

		if (close(D[0], 0))
		{
			parX = 1;
			if ((hi < P[0]) || (low > P[0]))
			{
				i--;
				continue;
			}
		}
		else
		{
			XRayMin = (hi - P[0]) / D[0];
			XRayMax = (low - P[0]) / D[0];
			if (XRayMin > XRayMax)
			{
				temp = XRayMin;
				XRayMin = XRayMax;
				XRayMax = temp;
			}

			if ((XRayMin > Depth2) || (XRayMax < Depth1))
			{
				i--;
				continue;
			}

			if ((TPotRes = XRayMin) > TResult)
			{
				i--;
				continue;
			}

			TLen = XRayMax - XRayMin;
		}

		/* Y */
		if (SectorNum[i] < MaxPrecompY)
		{
			low = PData->Low[1][SectorNum[i]];
			hi = PData->Hi[1][SectorNum[i]];
		}
		else
			Evaluate_Function_Interval_UV(*(Par->Function[1]), Par->accuracy, low_vect, hi_vect, Par->max_gradient, low, hi);

		if (close(D[1], 0))
		{
			parY = 1;
			if ((hi < P[1]) || (low > P[1]))
			{
				i--;
				continue;
			}
		}
		else
		{
			YRayMin = (hi - P[1]) / D[1];
			YRayMax = (low - P[1]) / D[1];
			if (YRayMin > YRayMax)
			{
				temp = YRayMin;
				YRayMin = YRayMax;
				YRayMax = temp;
			}
			if ((YRayMin > Depth2) || (YRayMax < Depth1))
			{
				i--;
				continue;
			}
			if ((TPotRes = YRayMin) > TResult)
			{
				i--;
				continue;
			}
			if (parX == 0)
			{
				if ((YRayMin > XRayMax) || (YRayMax < XRayMin))
				{
					i--;
					continue;
				}
			}
			if ((temp = YRayMax - YRayMin) > TLen)
				TLen = temp;
		}

		/* Z */
		if ((SectorNum[i] < MaxPrecompZ) && (0 < SectorNum[i]))
		{
			low = PData->Low[2][SectorNum[i]];
			hi = PData->Hi[2][SectorNum[i]];
		}
		else
			Evaluate_Function_Interval_UV(*(Par->Function[2]), Par->accuracy, low_vect, hi_vect, Par->max_gradient, low, hi);

		if (close(D[2], 0))
		{
			if ((hi < P[2]) || (low > P[2]))
			{
				i--;
				continue;
			}
		}
		else
		{
			ZRayMin = (hi - P[2]) / D[2];
			ZRayMax = (low - P[2]) / D[2];
			if (ZRayMin > ZRayMax)
			{
				temp = ZRayMin;
				ZRayMin = ZRayMax;
				ZRayMax = temp;
			}
			if ((ZRayMin > Depth2) || (ZRayMax < Depth1))
			{
				i--;
				continue;
			}
			if ((TPotRes = ZRayMin) > TResult)
			{
				i--;
				continue;
			}
			if (parX == 0)
			{
				if ((ZRayMin > XRayMax) || (ZRayMax < XRayMin))
				{
					i--;
					continue;
				}
			}
			if (parY == 0)
			{
				if ((ZRayMin > YRayMax) || (ZRayMax < YRayMin))
				{
					i--;
					continue;
				}
			}
			if ((temp = ZRayMax - ZRayMin) > TLen)
				TLen = temp;
		}

		if (Len > TLen)
			Len = TLen;
		if (Len < Par->accuracy)
		{
			if ((TResult > TPotRes) && (TPotRes > Depth1))
			{
				TResult = TPotRes;
				Par->last_u = UResult = low_vect[U];
				Par->last_v = VResult = low_vect[V];
			}
			i--;
		}
		else
		{
			/* 1 copy */
			if ((SectorNum[i] *= 2) >= Max_intNumber)
				SectorNum[i] = Max_intNumber;
			SectorNum[i + 1] = SectorNum[i];
			SectorNum[i]++;
			i++;
			Intervals_Low[INDEX_U][i] = low_vect[U];
			Intervals_Hi[INDEX_U][i] = hi_vect[U];

			Intervals_Low[INDEX_V][i] = low_vect[V];
			Intervals_Hi[INDEX_V][i] = hi_vect[V];

			/* 2 split */
			temp = (Intervals_Hi[split][i] + Intervals_Low[split][i]) / 2.0;
			Intervals_Hi[split][i] = temp;
			Intervals_Low[split][i - 1] = temp;
		}
	}

	if (TResult < Depth2)
	{
		Increase_Counter(stats[Ray_Parametric_Tests_Succeeded]);
		VScale(IPoint, Ray->Direction, TResult);
		VAddEq(IPoint, Ray->Initial);

		if (Point_In_Clip(IPoint, Par->Clip))
		{
			/*
			  compute_param_normal( Par, UResult, VResult , &N); 
			  push_normal_entry( TResult ,IPoint, N, (OBJECT *) Object, Depth_Stack);
			*/
//			UV_VECT uv;
//			Make_UV_Vector(uv, UResult, VResult);
//			push_uv_entry(TResult, IPoint, uv, (OBJECT *)Object, Depth_Stack);
			push_entry(TResult, IPoint, (OBJECT *)Object, Depth_Stack);

			return true;
		}
	}

	return false;
}
Beispiel #27
0
bool Fractal::All_Intersections(const Ray& ray, IStack& Depth_Stack, TraceThreadData *Thread)
{
    bool Intersection_Found;
    bool LastIsInside = false;
    bool CurrentIsInside, NextIsInside;
    DBL Depth, Depth_Max;
    DBL Dist, Dist_Next, LenSqr, LenInv;

    Vector3d IPoint, Mid_Point, Next_Point, Real_Pt;
    Vector3d Real_Normal, F_Normal;
    Vector3d Direction;
    BasicRay New_Ray;

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

    Intersection_Found = false;

    /* Get into Fractal's world. */

    if (Trans != NULL)
    {
        MInvTransDirection(Direction, ray.Direction, Trans);
        LenSqr = Direction.lengthSqr();

        if (LenSqr == 0.0)
        {
            return (false);
        }

        if (LenSqr != 1.0)
        {
            LenInv = 1.0 / sqrt(LenSqr);
            Direction *= LenInv;
        }
        else
            LenInv = 1.0;

        New_Ray.Direction = Direction;
        MInvTransPoint(New_Ray.Origin, ray.Origin, Trans);
    }
    else
    {
        Direction = ray.Direction;
        New_Ray = ray;
        LenInv = 1.0;
    }

    /* Bound fractal. */

    if (!F_Bound(New_Ray, this, &Depth, &Depth_Max))
    {
        return (false);
    }

    if (Depth_Max < Fractal_Tolerance)
    {
        return (false);
    }

    if (Depth < Fractal_Tolerance)
    {
        Depth = Fractal_Tolerance;
    }

    /* Jump to starting point */

    Next_Point = New_Ray.Origin + Direction * Depth;

    CurrentIsInside = D_Iteration(Next_Point, this, Direction, &Dist, Thread->Fractal_IStack);

    /* Light ray starting inside ? */

    if (CurrentIsInside)
    {
        Next_Point += (2.0 * Fractal_Tolerance) * Direction;

        Depth += 2.0 * Fractal_Tolerance;

        if (Depth > Depth_Max)
        {
            return (false);
        }

        CurrentIsInside = D_Iteration(Next_Point, this, Direction, &Dist, Thread->Fractal_IStack);
    }

    /* Ok. Trace it */

    while (Depth < Depth_Max)
    {
        /*
         * Get close to the root: Advance with Next_Point, keeping track of last
         * position in IPoint...
         */

        while (1)
        {
            if (Dist < Precision)
                Dist = Precision;

            Depth += Dist;

            if (Depth > Depth_Max)
            {
                if (Intersection_Found)
                    Thread->Stats()[Ray_Fractal_Tests_Succeeded]++;
                return (Intersection_Found);
            }

            IPoint = Next_Point;
            Next_Point += Dist * Direction;

            NextIsInside = D_Iteration(Next_Point, this, Direction, &Dist_Next, Thread->Fractal_IStack);

            if (NextIsInside != CurrentIsInside)
            {
                /* Set surface was crossed... */

                Depth -= Dist;
                break;
            }
            else
            {
                Dist = Dist_Next; /* not reached */
            }
        }

        /* then, polish the root via bisection method... */

        while (Dist > Fractal_Tolerance)
        {
            Dist *= 0.5;
            Mid_Point = IPoint + Dist * Direction;

            LastIsInside = Iteration(Mid_Point, this, Thread->Fractal_IStack);

            if (LastIsInside == CurrentIsInside)
            {
                IPoint = Mid_Point;

                Depth += Dist;

                if (Depth > Depth_Max)
                {
                    if (Intersection_Found)
                        Thread->Stats()[Ray_Fractal_Tests_Succeeded]++;
                    return (Intersection_Found);
                }
            }
        }

        if (!CurrentIsInside) /* Mid_Point isn't inside the set */
        {
            IPoint += Dist * Direction;

            Depth += Dist;

            Iteration(IPoint, this, Thread->Fractal_IStack);
        }
        else
        {
            if (LastIsInside != CurrentIsInside)
            {
                Iteration(IPoint, this, Thread->Fractal_IStack);
            }
        }

        if (Trans != NULL)
        {
            MTransPoint(Real_Pt, IPoint, Trans);
            Normal_Calc(this, F_Normal, Thread->Fractal_IStack);
            MTransNormal(Real_Normal, F_Normal, Trans);
        }
        else
        {
            Real_Pt = IPoint;
            Normal_Calc(this, Real_Normal, Thread->Fractal_IStack);
        }

        if (Clip.empty() || Point_In_Clip(Real_Pt, Clip, Thread))
        {
            Real_Normal.normalize();
            Depth_Stack->push(Intersection(Depth * LenInv, Real_Pt, Real_Normal, this));
            Intersection_Found = true;

            /* If fractal isn't used with CSG we can exit now. */

            if (!(Type & IS_CHILD_OBJECT))
            {
                break;
            }
        }

        /* Start over where work was left */

        IPoint = Next_Point;
        Dist = Dist_Next;
        CurrentIsInside = NextIsInside;

    }

    if (Intersection_Found)
        Thread->Stats()[Ray_Fractal_Tests_Succeeded]++;
    return (Intersection_Found);
}
Beispiel #28
0
int Cone::Intersect(const BasicRay& ray, CONE_INT *Intersection, TraceThreadData *Thread) const
{
    int i = 0;
    DBL a, b, c, z, t1, t2, len;
    DBL d;
    Vector3d P, D;

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

    /* Transform the ray into the cones space */

    MInvTransPoint(P, ray.Origin, Trans);
    MInvTransDirection(D, ray.Direction, Trans);

    len = D.length();
    D /= len;

    if (Test_Flag(this, CYLINDER_FLAG))
    {
        /* Solve intersections with a cylinder */

        a = D[X] * D[X] + D[Y] * D[Y];

        if (a > EPSILON)
        {
            b = P[X] * D[X] + P[Y] * D[Y];

            c = P[X] * P[X] + P[Y] * P[Y] - 1.0;

            d = b * b - a * c;

            if (d >= 0.0)
            {
                d = sqrt(d);

                t1 = (-b + d) / a;
                t2 = (-b - d) / a;

                z = P[Z] + t1 * D[Z];

                if ((t1 > Cone_Tolerance) && (t1 < MAX_DISTANCE) && (z >= 0.0) && (z <= 1.0))
                {
                    Intersection[i].d   = t1 / len;
                    Intersection[i++].t = SIDE_HIT;
                }

                z = P[Z] + t2 * D[Z];

                if ((t2 > Cone_Tolerance) && (t2 < MAX_DISTANCE) && (z >= 0.0) && (z <= 1.0))
                {
                    Intersection[i].d   = t2 / len;
                    Intersection[i++].t = SIDE_HIT;
                }
            }
        }
    }
    else
    {
        /* Solve intersections with a cone */

        a = D[X] * D[X] + D[Y] * D[Y] - D[Z] * D[Z];

        b = D[X] * P[X] + D[Y] * P[Y] - D[Z] * P[Z];

        c = P[X] * P[X] + P[Y] * P[Y] - P[Z] * P[Z];

        if (fabs(a) < EPSILON)
        {
            if (fabs(b) > EPSILON)
            {
                /* One intersection */

                t1 = -0.5 * c / b;

                z = P[Z] + t1 * D[Z];

                if ((t1 > Cone_Tolerance) && (t1 < MAX_DISTANCE) && (z >= dist) && (z <= 1.0))
                {
                    Intersection[i].d   = t1 / len;
                    Intersection[i++].t = SIDE_HIT;
                }
            }
        }
        else
        {
            /* Check hits against the side of the cone */

            d = b * b - a * c;

            if (d >= 0.0)
            {
                d = sqrt(d);

                t1 = (-b - d) / a;
                t2 = (-b + d) / a;

                z = P[Z] + t1 * D[Z];

                if ((t1 > Cone_Tolerance) && (t1 < MAX_DISTANCE) && (z >= dist) && (z <= 1.0))
                {
                    Intersection[i].d   = t1 / len;
                    Intersection[i++].t = SIDE_HIT;
                }

                z = P[Z] + t2 * D[Z];

                if ((t2 > Cone_Tolerance) && (t2 < MAX_DISTANCE) && (z >= dist) && (z <= 1.0))
                {
                    Intersection[i].d   = t2 / len;
                    Intersection[i++].t = SIDE_HIT;
                }
            }
        }
    }

    if (Test_Flag(this, CLOSED_FLAG) && (fabs(D[Z]) > EPSILON))
    {
        d = (1.0 - P[Z]) / D[Z];

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

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

        if (((Sqr(a) + Sqr(b)) <= 1.0) && (d > Cone_Tolerance) && (d < MAX_DISTANCE))
        {
            Intersection[i].d   = d / len;
            Intersection[i++].t = CAP_HIT;
        }

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

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

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

        if ((Sqr(a) + Sqr(b)) <= (Test_Flag(this, CYLINDER_FLAG) ? 1.0 : Sqr(dist))
            && (d > Cone_Tolerance) && (d < MAX_DISTANCE))
        {
            Intersection[i].d   = d / len;
            Intersection[i++].t = BASE_HIT;
        }
    }

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

    return (i);
}
Beispiel #29
0
void Warp_EPoint (VECTOR TPoint, VECTOR EPoint, TPATTERN *TPat)
{
   VECTOR PTurbulence,RP;
   int Axis,i,temp_rand;
   int blockX = 0, blockY = 0, blockZ = 0 ;
   SNGL BlkNum;
   DBL  Length;
   DBL  Strength;
   WARP *Warp=TPat->Warps;
   TURB *Turb;
   TRANS *Tr;
   REPEAT *Repeat;
   BLACK_HOLE *Black_Hole;
   VECTOR Delta, Center;

   Assign_Vector(TPoint, EPoint);

   while (Warp != NULL)
   {
      switch(Warp->Warp_Type)
      {
        case CLASSIC_TURB_WARP:
          if ((TPat->Type == MARBLE_PATTERN) ||
              (TPat->Type == NO_PATTERN)     ||
              (TPat->Type == WOOD_PATTERN))
          {
             break;
          }
        /* If not a special type, fall through to next case */

        case EXTRA_TURB_WARP:
          Turb=(TURB *)Warp;
          DTurbulence (PTurbulence, TPoint, Turb);
          TPoint[X] += PTurbulence[X] * Turb->Turbulence[X];
          TPoint[Y] += PTurbulence[Y] * Turb->Turbulence[Y];
          TPoint[Z] += PTurbulence[Z] * Turb->Turbulence[Z];
          break;

        case NO_WARP:
          break;

        case TRANSFORM_WARP:
          Tr=(TRANS *)Warp;
          MInvTransPoint(TPoint, TPoint, &(Tr->Trans));
          break;

        case REPEAT_WARP:
          Repeat=(REPEAT *)Warp;
          Assign_Vector(RP,TPoint);
          Axis=Repeat->Axis;
          BlkNum=(SNGL)floor(TPoint[Axis]/Repeat->Width);
          
          RP[Axis]=TPoint[Axis]-BlkNum*Repeat->Width;
          
          if (((int)BlkNum) & 1)
          {          
             VEvaluateEq(RP,Repeat->Flip);
             if ( Repeat->Flip[Axis] < 0 ) 
             {
                RP[Axis] = Repeat->Width+RP[Axis];
             }
          }

          VAddScaledEq(RP,BlkNum,Repeat->Offset);
          Assign_Vector(TPoint,RP);
          break;

        case BLACK_HOLE_WARP:
          Black_Hole = (BLACK_HOLE *) Warp ;
          Assign_Vector (Center, Black_Hole->Center) ;

          if (Black_Hole->Repeat)
          {
            /* first, get the block number we're in for each dimension  */
            /* block numbers are (currently) calculated relative to 0   */
            /* we use floor () since it correctly returns -1 for the
               first block below 0 in each axis                         */
            /* one final point - we could run into overflow problems if
               the repeat vector was small and the scene very large.    */
            if (Black_Hole->Repeat_Vector [X] >= Small_Tolerance)
              blockX = (int) floor (TPoint [X] / Black_Hole->Repeat_Vector [X]) ;

            if (Black_Hole->Repeat_Vector [Y] >= Small_Tolerance)
              blockY = (int) floor (TPoint [Y] / Black_Hole->Repeat_Vector [Y]) ;

            if (Black_Hole->Repeat_Vector [Z] >= Small_Tolerance)
              blockZ = (int) floor (TPoint [Z] / Black_Hole->Repeat_Vector [Z]) ;

            if (Black_Hole->Uncertain)
            {
              /* if the position is uncertain calculate the new one first */
              /* this will allow the same numbers to be returned by frand */
              
              temp_rand = POV_GET_OLD_RAND(); /*protect seed*/
  
              POV_SRAND (Hash3d (blockX, blockY, blockZ)) ;
              Center [X] += FRAND () * Black_Hole->Uncertainty_Vector [X] ;
              Center [Y] += FRAND () * Black_Hole->Uncertainty_Vector [Y] ;
              Center [Z] += FRAND () * Black_Hole->Uncertainty_Vector [Z] ;
              POV_SRAND (temp_rand) ;  /*restore*/
            }

            Center [X] += Black_Hole->Repeat_Vector [X] * blockX ;
            Center [Y] += Black_Hole->Repeat_Vector [Y] * blockY ;
            Center [Z] += Black_Hole->Repeat_Vector [Z] * blockZ ;
          }

          VSub (Delta, TPoint, Center) ;
          VLength (Length, Delta) ;

          /* Length is the distance from the centre of the black hole */
          if (Length >= Black_Hole->Radius) break ;

          if (Black_Hole->Type == 0)
          {
            /* now convert the length to a proportion (0 to 1) that the point
               is from the edge of the black hole. a point on the perimeter
               of the black hole will be 0.0 ; a point at the centre will be
               1.0 ; a point exactly halfway will be 0.5, and so forth. */
            Length = (Black_Hole->Radius - Length) / Black_Hole->Radius ;

            /* Strength is the magnitude of the transformation effect. firstly,
               apply the Power variable to Length. this is meant to provide a
               means of controlling how fast the power of the Black Hole falls
               off from its centre. if Power is 2.0, then the effect is inverse
               square. increasing power will cause the Black Hole to be a lot
               weaker in its effect towards its perimeter. 
               
               finally we multiply Strength with the Black Hole's Strength
               variable. if the resultant value exceeds 1.0 we clip it to 1.0.
               this means a point will never be transformed by more than its
               original distance from the centre. the result of this clipping
               is that you will have an 'exclusion' area near the centre of
               the black hole where all points whose final value exceeded or
               equalled 1.0 were moved by a fixed amount. this only happens
               if the Strength value of the Black Hole was greater than one. */

            Strength = pow (Length, Black_Hole->Power) * Black_Hole->Strength ;
            if (Strength > 1.0) Strength = 1.0 ;
            
            /* if the Black Hole is inverted, it gives the impression of 'push-
               ing' the pattern away from its centre. otherwise it sucks. */
            VScaleEq (Delta, Black_Hole->Inverted ? -Strength : Strength) ;

            /* add the scaled Delta to the input point to end up with TPoint. */
            VAddEq (TPoint, Delta) ;
          }
          break;
          
        /* 10/23/1998 Talious added SPherical Cylindrical and toroidal
        warps */

        case CYLINDRICAL_WARP:
          warp_cylindrical(TPoint, (CYLW *)Warp);
          break;

        case PLANAR_WARP:
          warp_planar(TPoint, (PLANARW *)Warp);
          break;
      
        case SPHERICAL_WARP:
          warp_spherical(TPoint, (SPHEREW *)Warp);
          break;

        case TOROIDAL_WARP:
          warp_toroidal(TPoint, (TOROIDAL *) Warp);
          break;
          
        default:
          Error("Warp type %d not yet implemented",Warp->Warp_Type);
      }
      Warp=Warp->Next_Warp;
   }

   for (i=X; i<=Z; i++)
     if (TPoint[i] > COORDINATE_LIMIT)
       TPoint[i]= COORDINATE_LIMIT;
     else
       if (TPoint[i] < -COORDINATE_LIMIT)
         TPoint[i] = -COORDINATE_LIMIT;

}
Beispiel #30
0
static void IsoSurface_Normal(VECTOR Result, OBJECT* Object, INTERSECTION* Inter)
{
	VECTOR New_Point, TPoint;
	ISOSURFACE *Isosrf = (ISOSURFACE *)Object;
	FUNCTION Function = *(((ISOSURFACE *)Object)->Function);
	DBL funct;

	switch (Inter->i1)
	{
		case SIDE_X_0:
			Make_Vector(Result, -1.0, 0.0, 0.0);
			break;
		case SIDE_X_1:
			Make_Vector(Result, 1.0, 0.0, 0.0);
			break;
		case SIDE_Y_0:
			Make_Vector(Result, 0.0, -1.0, 0.0);
			break;
		case SIDE_Y_1:
			Make_Vector(Result, 0.0, 1.0, 0.0);
			break;
		case SIDE_Z_0:
			Make_Vector(Result, 0.0, 0.0, -1.0);
			break;
		case SIDE_Z_1:
			Make_Vector(Result, 0.0, 0.0, 1.0);
			break;

		default:

			/* Transform the point into the isosurface space */
			if(((ISOSURFACE *)Object)->Trans != NULL)
				MInvTransPoint(New_Point, Inter->IPoint, Isosrf->Trans);
			else
				Assign_Vector(New_Point, Inter->IPoint);

			if(Isosrf->container_shape)
			{
				VSub(Result, New_Point, Isosrf->container.sphere.center);
				VLength(funct, Result);
				if(fabs(funct - Isosrf->container.sphere.radius) < EPSILON)
				{
					VInverseScaleEq(Result, Isosrf->container.sphere.radius);
					break;
				}
			}

			Assign_Vector(TPoint, New_Point);
			funct = Evaluate_Function(Function, TPoint);
			Assign_Vector(TPoint, New_Point);
			TPoint[X] += Isosrf->accuracy;
			Result[X] = Evaluate_Function(Function, TPoint) - funct;
			Assign_Vector(TPoint, New_Point);
			TPoint[Y] += Isosrf->accuracy;
			Result[Y] = Evaluate_Function(Function, TPoint) - funct;
			Assign_Vector(TPoint, New_Point);
			TPoint[Z] += Isosrf->accuracy;
			Result[Z] = Evaluate_Function(Function, TPoint) - funct;

			if((Result[X] == 0) && (Result[Y] == 0) && (Result[Z] == 0))
				Result[X] = 1.0;
			VNormalize(Result, Result);
	}


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

	if(((ISOSURFACE *)Object)->Trans != NULL)
	{
		MTransNormal(Result, Result, ((ISOSURFACE *)Object)->Trans);

		VNormalize(Result, Result);
	}
}