int Intersect_BCyl(BCYL *BCyl, VECTOR P, VECTOR  D)
{
  int i, cnt;
  DBL dist[8];
  BCYL_INT Inter;
  BCYL_INT *intervals;
  BCYL_ENTRY *Entry;

  cnt = 0;

  Inter.d[1] = 0.0;

  /* Intersect all cylinder and plane elements. */

  intersect_bound_elements(BCyl, P, D);

  /* Intersect all spline segments. */

  intervals = BCyl->intervals;

  for (i = 0; i < BCyl->number; i++)
  {
    Entry = &BCyl->entry[i];

    switch (intersect_thick_cylinder(BCyl, Entry, dist))
    {
      case 0:
        break;

      case 2:

        if (dist[0] > EPSILON)
        {
          Inter.d[0] = dist[0];
          Inter.n    = i;

          insert_hit(&Inter, intervals, &cnt);
        }
        else
        {
          if (dist[1] > EPSILON)
          {
            Inter.d[0] = 0.0;
            Inter.n    = i;

            insert_hit(&Inter, intervals, &cnt);
          }
        }

        break;

      case 4:

        if (dist[0] > EPSILON)
        {
          Inter.d[0] = dist[0];
          Inter.n    = i;

          insert_hit(&Inter, intervals, &cnt);
        }
        else
        {
          if (dist[1] > EPSILON)
          {
            Inter.d[0] = 0.0;
            Inter.n    = i;

            insert_hit(&Inter, intervals, &cnt);
          }
          else
          {
            if (dist[2] > EPSILON)
            {
              Inter.d[0] = dist[2];
              Inter.n    = i;

              insert_hit(&Inter, intervals, &cnt);
            }
            else
            {
              if (dist[3] > EPSILON)
              {
                Inter.d[0] = 0.0;
                Inter.n    = i;

                insert_hit(&Inter, intervals, &cnt);
              }
            }
          }
        }

        break;

      default:

        /*
         * We weren't able to find an even number of intersections. Thus
         * we can't tell where the ray enters and leaves the bounding
         * cylinder. To avoid problems we assume that the ray is always
         * inside the cylinder in that case.
         */

        Inter.d[0] = dist[0];
        Inter.n    = i;

        insert_hit(&Inter, intervals, &cnt);

        break;
    }
  }

  return(cnt);
}
Exemple #2
0
bool Superellipsoid::Intersect(const BasicRay& ray, IStack& Depth_Stack, TraceThreadData *Thread)
{
    int i, cnt, Found = false;
    DBL dists[PLANECOUNT+2];
    DBL t, t1, t2, v0, v1, len;
    Vector3d P, D, P0, P1, P2, P3;

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

    MInvTransPoint(P, ray.Origin, Trans);

    MInvTransDirection(D, ray.Direction, Trans);

    len = D.length();

    D /= len;

    /* Intersect superellipsoid's bounding box. */

    if (!intersect_box(P, D, &t1, &t2))
    {
        return(false);
    }

    /* Test if superellipsoid lies 'behind' the ray origin. */

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

    cnt = 0;

    if (t1 < DEPTH_TOLERANCE)
    {
        t1 = DEPTH_TOLERANCE;
    }

    dists[cnt++] = t1;
    dists[cnt++] = t2;

    /* Intersect ray with planes cutting superellipsoids in pieces. */

    cnt = find_ray_plane_points(P, D, cnt, dists, t1, t2);

    if (cnt <= 1)
    {
        return(false);
    }

    P0 = P + dists[0] * D;

    v0 = evaluate_superellipsoid(P0);

    if (fabs(v0) < ZERO_TOLERANCE)
    {
        if (insert_hit(ray, dists[0] / len, Depth_Stack, Thread))
        {
            if (Type & IS_CHILD_OBJECT)
            {
                Found = true;
            }
            else
            {
                return(true);
            }
        }
    }

    for (i = 1; i < cnt; i++)
    {
        P1 = P + dists[i] * D;

        v1 = evaluate_superellipsoid(P1);

        if (fabs(v1) < ZERO_TOLERANCE)
        {
            if (insert_hit(ray, dists[i] / len, Depth_Stack, Thread))
            {
                if (Type & IS_CHILD_OBJECT)
                {
                    Found = true;
                }
                else
                {
                    return(true);
                }
            }
        }
        else
        {
            if (v0 * v1 < 0.0)
            {
                /* Opposite signs, there must be a root between */

                solve_hit1(v0, P0, v1, P1, P2);

                P3 = P2 - P;

                t = P3.length();

                if (insert_hit(ray, t / len, Depth_Stack, Thread))
                {
                    if (Type & IS_CHILD_OBJECT)
                    {
                        Found = true;
                    }
                    else
                    {
                        return(true);
                    }
                }
            }
            else
            {
                /*
                 * Although there was no sign change, we may actually be approaching
                 * the surface. In this case, we are being fooled by the shape of the
                 * surface into thinking there isn't a root between sample points.
                 */

                if (check_hit2(P, D, dists[i-1], P0, v0, dists[i], &t, P2))
                {
                    if (insert_hit(ray, t / len, Depth_Stack, Thread))
                    {
                        if (Type & IS_CHILD_OBJECT)
                        {
                            Found = true;
                        }
                        else
                        {
                            return(true);
                        }
                    }
                    else
                    {
                        break;
                    }
                }
            }
        }

        v0 = v1;

        P0 = P1;
    }

    return(Found);
}