0

I am working on function to determine if a circle and a ray intersect each other. The base of the function comes from this website specifically this page. In the notes on the first page where the author discusses circle and ray intersection he lists this about determining if a circle and ray intersect

The exact behavior is determined by the expression within the square root b * b - 4 * a * c

  • If this is less than 0 then the line does not intersect the sphere.

  • If it equals 0 then the line is a tangent to the sphere intersecting it at one point, namely at u = -b/2a.

  • If it is greater then 0 the line intersects the sphere at two points.

This is where the problem in my code lies. It lies the comparison of the double bb4ac in the function below.

bool CircleRayIntersect(double ip1_x, double ip1_y, double ip2_x, double ip2_y,
                                double isc_x, double isc_y, double isc_r,
                                double &out1_x, double &out1_y,
                                double &out2_x, double &out2_y)
{
    double a,b,c; 
    double bb4ac;
    double r = isc_r;
    double dp_x;
    double dp_y;
    double mu_1;
    double mu_2;
    double p1_x = ip1_x;
    double p1_y = ip1_y;
    double p2_x = ip2_x;
    double p2_y = ip2_y;
    double sc_x = isc_x;
    double sc_y = isc_y;

    dp_x = p2_x - p1_x;
    dp_y = p2_y - p1_y;
    a = dp_x * dp_x + dp_y * dp_y;
    b = 2 * (dp_x * (p1_x - sc_x) + dp_y * (p1_y - sc_y));
    c = sc_x * sc_x + sc_y * sc_y ;
    c += p1_x * p1_x + p1_y * p1_y;
    c -= 2 * (sc_x * p1_x + sc_y * p1_y);
    c -= r * r;
    bb4ac = b * b - 4 * a * c;

    // Checks to make sure that the line actually intersects
    TRACE("  -- Checking     a: %f\n", a);
    TRACE("  -- Checking bb4ac: %f\n", bb4ac);

    if (abs(a) < 1E-9 || bb4ac < 0.0) 
    {

        if(bb4ac < 0.0)
        {
            TRACE("bb4ac is less than zero: %d < 0.0 = %d\n", bb4ac, (bb4ac < 0.0));
            TRACE("bb4ac is less than zero: %f < 0.0 = %f\n", bb4ac, (bb4ac < 0.0));
        }
        if (abs(a) < 1E-9)
            TRACE("abs(a) is less than zero\n");

        mu_1 = 0;
        mu_2 = 0;
        TRACE("Ray does not intersect with circle!\n");
        return FALSE;
    }

    mu_1 = (-b + sqrt(bb4ac)) / (2 * a);
    mu_2 = (-b - sqrt(bb4ac)) / (2 * a);

    out1_x = p1_x + (mu_1*(p2_x-p1_x));
    out1_y = p1_y + (mu_1*(p2_y-p1_y));
    out2_x = p1_x + (mu_2*(p2_x-p1_x));
    out2_y = p1_y + (mu_2*(p2_y-p1_y));

    return TRUE;
}

At some points, when this code is called with certain arguments bb4ac ends up being equal to -0.0. When this happens the checking of bb4ac against the rules listed above becomes broken. Here is some sample output from the TRACE statements when bb4ac is -0.0.

  -- Checking     a: 129.066667
  -- Checking bb4ac: -0.000000
bb4ac is less than zero: 0 < 0.0 = -1114636288
bb4ac is less than zero: -0.000000 < 0.0 = 0.000000

Judging by the output of the TRACE it looks like the if(..) statement that compares bb4ac with 0 does not interpret bb4ac properly. Seeing that bb4ac is printed as -1114636288 when interpreted with the %d flag and -0.000 when interpreted with the %f flag, I would have to think that bb4ac is being interpreted into -1114636288 in the if statement and not -0.000.

How can I write the if statement to properly interpret bb4ac as -0.000? Why is it seeing it as that in the first place?

AnotherUser
  • 1,311
  • 1
  • 14
  • 35
  • You're messing up the types for `printf`, which is Undefined Behavior and often causes stack corruption. And since it's UB, none of your results are meaningful - technically not even those preceding the UB! – MSalters Jul 23 '14 at 07:20

2 Answers2

1

Assuming TRACE is a printf-like varargs function, using %d with a double argument, or %f with an int or bool argument is undefined behavior. Use the correct format specifiers or cast the argument to the correct type.

ecatmur
  • 152,476
  • 27
  • 293
  • 366
  • What is a varargs function? Variable arguments? – AnotherUser Jul 22 '14 at 12:45
  • @AnotherUser like `printf`, using format specifiers to determine how to access variable argument: http://en.cppreference.com/w/cpp/language/variadic_arguments. – ecatmur Jul 22 '14 at 12:46
  • Does this answer mean my TRACE statements are altering the outcome of the comparison or is this just a side note? // If I want to print a double, I should use `%f`? – AnotherUser Jul 22 '14 at 12:51
  • @AnotherUser "I would have to think that bb4ac is being interpreted into -1114636288 in the if statement" - the premise of your question is incorrect. – ecatmur Jul 22 '14 at 12:57
  • @AnotherUser if you want to print a double, you should use `%g`. – ecatmur Jul 22 '14 at 12:58
  • Could you pass me a source for that, not that I don't believe you. I just don't know anything about the format specifiers and I have never found something good. – AnotherUser Jul 22 '14 at 13:03
  • @AnotherUser I would use http://en.cppreference.com/w/cpp/io/c/printf - apologies if it's too terse. – ecatmur Jul 22 '14 at 13:06
  • Probably the reason I am here is because I like the terse. – AnotherUser Jul 22 '14 at 13:14
0

It seems you are familiar with the fact that double comparison should never be precise(i.e. you should use tolerance), but you are not doing it quite right. To check if a number is less than zero:

if (x < -1E-9)

To check if a number is greater than zero:

if (x > 1E-9)

To check if a number is zero:

if (x > -1E-9 && x < 1E-9)
Ivaylo Strandjev
  • 69,226
  • 18
  • 123
  • 176
  • 1
    Actually, he might find [this](http://stackoverflow.com/q/13698927/2508277) interesting. – Unda Jul 22 '14 at 12:45