Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 6992041
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 27, 20262026-05-27T19:35:01+00:00 2026-05-27T19:35:01+00:00

I am debugging an algorithm I wrote that converts a complex, self-intersecting polygon into

  • 0

I am debugging an algorithm I wrote that converts a complex, self-intersecting polygon into a simple polygon by means of identifying all intersection points, and walking around the outside perimeter.

I wrote a series of random data generating stress tests, and in this one, I encountered an interesting situation that caused my algorithm to fail, after working correctly thousands upon thousands of times.

double fRand(double fMin, double fMax)
{
    double f = (double)rand() / RAND_MAX; // On my machine RAND_MAX = 2147483647
    return fMin + f * (fMax - fMin);
}
// ... testing code below:  
srand(1);
for(int j=3;j<5000;j+=5) {
    std::vector<E_Point> geometry;
    for(int i=0;i<j;i++) {
        double radius = fRand(0.6,1.0);
        double angle = fRand(0,2*3.1415926535);
        E_Point pt(cos(angle),sin(angle));
        pt *= radius;
        geometry.push_back(pt); // sending in a pile of shit
    }
    // run algorithm on this geometry

That was an overview of how this is relevant and how I got to where I am now. There are a lot more details I’m leaving out.

What I have been able to do is narrow the issue down to the segment-segment intersection code i am using:

bool intersect(const E_Point& a0, const E_Point& a1,
               const E_Point& b0, const E_Point& b1,
               E_Point& intersectionPoint) {

    if (a0 == b0 || a0 == b1 || a1 == b0 || a1 == b1) return false;
    double x1 = a0.x; double y1 = a0.y;
    double x2 = a1.x; double y2 = a1.y;
    double x3 = b0.x; double y3 = b0.y;
    double x4 = b1.x; double y4 = b1.y;

    //AABB early exit
    if (b2Max(x1,x2) < b2Min(x3,x4) || b2Max(x3,x4) < b2Min(x1,x2) ) return false;
    if (b2Max(y1,y2) < b2Min(y3,y4) || b2Max(y3,y4) < b2Min(y1,y2) ) return false;

    float ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3));
    float ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3));
    float denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
    // check against epsilon (lowest normalized double value)
    if (fabs(denom) < DBL_EPSILON) {
        //Lines are too close to parallel to call
        return false;
    }
    ua /= denom;
    ub /= denom;

    if ((0 < ua) && (ua < 1) && (0 < ub) && (ub < 1)) {
        intersectionPoint.x = (x1 + ua * (x2 - x1));
        intersectionPoint.y = (y1 + ua * (y2 - y1));
        return true;
    }
    return false;
}

What’s happening is that I have two intersections that this function returns the exact same intersection point value for. Here is a very zoomed in view of the relevant geometry:

enter image description here

The vertical line is defined by the points
(0.3871953044519425, -0.91857980824611341), (0.36139704793723609, 0.91605957361605106)

the green nearly-horizontal line by the points (0.8208980020500205, 0.52853407296583088), (0.36178501611208552, 0.88880385168617226)

and the white line by (0.36178501611208552, 0.88880385168617226), (-0.43211245441046209, 0.68034202227710472)

As you can see the last two lines do share a common point.

My function gives me a solution of (0.36178033094571277, 0.88880245640159794)
for BOTH of these intersections (one of which you see in the picture as a red dot).

The reason why this is a big problem, is that my perimeter algorithm depends on sorting the intersection points on each edge. Since both of these intersection points were calculated to have the same exact value, the sort put them in the wrong orientation. The path of the perimeter comes from above, and followed the white line left, rather than the green line left, meaning that I was no longer following the outside perimeter of my polygon shape.

To fix this problem, there are probably a lot of things I can do but I do not want to search through all of the intersection lists to check against other points to see if the positions compare equal. A better solution would be to try to increase the accuracy of my intersection function.

So what I’m asking is, why is the solution point so inaccurate? Is it because one of the lines is almost vertical? Should I be performing some kind of transformation first? In both cases the almost-vertical line was passed as a0 and a1.

Update: Hey, look at this:

TEST(intersection_precision_test) {
    E_Point problem[] = {

    {0.3871953044519425, -0.91857980824611341}, // 1559
    {0.36139704793723609, 0.91605957361605106}, // 1560
    {-0.8208980020500205, 0.52853407296583088}, // 1798
    {0.36178501611208552, 0.88880385168617226}, // 1799
    {-0.43211245441046209, 0.6803420222771047} // 1800
    };
    std::cout.precision(16);
    E_Point result;
    intersect(problem[0],problem[1],problem[2],problem[3],result);
    std::cout << "1: " << result << std::endl;
    intersect(problem[0],problem[1],problem[3],problem[2],result);
    std::cout << "2: " << result << std::endl;
    intersect(problem[1],problem[0],problem[2],problem[3],result);
    std::cout << "3: " << result << std::endl;
    intersect(problem[1],problem[0],problem[3],problem[2],result);
    std::cout << "4: " << result << std::endl;

    intersect(problem[2],problem[3],problem[0],problem[1],result);
    std::cout << "rev: " << result << std::endl;
    intersect(problem[3],problem[2],problem[0],problem[1],result);
    std::cout << "revf1: " << result << std::endl;
    intersect(problem[2],problem[3],problem[1],problem[0],result);
    std::cout << "revf2: " << result << std::endl;
    intersect(problem[3],problem[2],problem[1],problem[0],result);
    std::cout << "revfboth: " << result << std::endl;
}

Output:

Starting Test intersection_precision_test, at Polygon.cpp:1830
1: <0.3617803309457128,0.8888024564015979>
2: <0.3617803309457128,0.8888024564015979>
3: <0.3617803314022162,0.8888024239374175>
4: <0.3617803314022162,0.8888024239374175>
rev: <0.3617803635476076,0.8888024344185281>
revf1: <0.3617803313928456,0.8888024246235207>
revf2: <0.3617803635476076,0.8888024344185281>
revfboth: <0.3617803313928456,0.8888024246235207>

Am I actually running out of mantissa bits or can I do significantly better with a smarter algorithm?

The problem here is that there’s no easy way for me to determine when a vertex is set really really close to another line. I wouldn’t mind moving it or even completely nuking it because neither of those will screw up my sort!

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-27T19:35:02+00:00Added an answer on May 27, 2026 at 7:35 pm

    If you change your float intermediates (ua, ub, denom) to doubles and print the ua values (after division), you’ll get these:

    0x1.f864ab6b36458p-1 in the first case
    0x1.f864af01f2037p-1 in the second case
    

    I’ve printed them in hex to make it easy to look at the bits. These two values agree in the first 22 bits (1.f864a plus the high bit of b and f). A float only has 23 bits of significand! It’s no surprise that if you compute your intermediates in floats, they get rounded to the same answer.

    In this case, you can perhaps work around the problem by computing your intermediates using doubles instead of floats. (I made my point struct use doubles for x and y. If you’re using floats, I don’t know if computing the intermediates in doubles will help.)

    However, a case where the vertical segment passes even closer to the intersection of the two horizontal segments might still require even more precision than a double can provide.

    What would you do if the vertical segment passed exactly through the shared endpoint of the horizontal segments? I assume you handle this case correctly.

    If you look at the ub values (after division), computed with doubles, you get these:

    0.9999960389052315
    5.904388076838819e-06
    

    This means that the intersection is very, very close to the shared endpoint of the horizontal segments.

    So here’s what I think you can do. Each time you compute an intersection, look at ub. If it’s sufficiently close to 1, move the endpoint to be the intersection point. Then treat the intersection as if it had been an exact pass-through case in the first place. You don’t really have to change the data, but you have to treat the endpoint as moved for both of the segments that share the endpoint, which means the current intersection test and the test on the next line segment.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I am debugging an algorithm that is being represented by a set of ViewModels.
After debugging a CodeIgniter application that were installed into a new development environment, I
Debugging with gdb, any c++ code that uses STL/boost is still a nightmare. Anyone
Debugging an operation that's performing slowly, I've discovered (to my astonishment) that the line:
While debugging the code in Eclipse, I runned into the following problem. There is
I'm currently debugging an algorithm I implemented in Haskell for my Diploma thesis. It
I did all sorts of debugging and referred to a multitude of sources and
I'm implementing the simple multiplication algorithm to compare its performance to a divide and
When debugging WCF service I need to use the remote share that stores our
While debugging an application using the Apache Zookeeper C runtime library, I run into

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.