A segment is defined by two endpoints $(x_1, y_1)$ and $(x_2, y_2)$.
The positive X axis for simplicity can be defined as the segment going from $(0, 0)$ to $(10^9, 0)$ (I'm working on a program where the maximum $X$ value is $10^6$ therefore this is good enough). Although a formula that doesn't rely on endpoints (for the axis) is also acceptable (and probably even better).
What I currently have is an algorithm that detects segment intersections, so I use the segment from $(0, 0)$ to $(10^9, 0)$ explained above. The algorithm I'm using is a $O(1)$ check that uses cross product for getting the orientation of points (code below).
But I'm wondering if there's a more elegant way to do this. I just want to refactor the code since this is the only intersection I need to do, and it looks a bit ugly to have all this code just for this. I suspect even a more elegant way would need some cross product stuff, but any idea is appreciated!
C++ code of my current algorithm.
struct Segment {
Point p, q;
int orientation(Point p, Point q, Point r) {
ll val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
if (val == 0) return 0;
return (val > 0) ? 1 : 2;
}
bool intersect(const Segment& s) {
Point p1 = p;
Point q1 = q;
Point p2 = s.p;
Point q2 = s.q;
int o1 = orientation(p1, q1, p2);
int o2 = orientation(p1, q1, q2);
int o3 = orientation(p2, q2, p1);
int o4 = orientation(p2, q2, q1);
return (o1 != o2 && o3 != o4);
}
};
If you trace the
intersectfunction step by step, and if you exclude the cases where $y_1 = 0$ and where $y_2 = 0,$ you might notice that two of the calls toorientationare merely testing whether $y_1 > 0$ and whether $y_2 > 0.$ Thereturnstatement then checks whether those two results are different, that is, whether $y_1$ and $y_2$ are on opposite sides of the $x$ axis.In the cases where $y_1 = 0$ and where $y_2 = 0,$ the two calls to
orientationwill return two different values (indicating an intersection with the $x$ axis) except, bizarrely, in the case where $y_1 = y_2 = 0$ (in which case the algorithm will tell you that the segment does not intersect the $x$ axis).One of the two remaining calls to
orientation-- the one that compares the point $(10^9, 0)$ with the points $(x_1, y_1)$ and $(x_2, y_2)$ -- is always going to return the same value as every other time, unless you're so unlucky that someone gives you points like $(x_1, y_1) = (10^9+1, 1)$ and $(x_2, y_2) = (10^9+1, -1).$ So ideally you would skip this call toorientationand merely check whether the one remaining call -- which compares $(0,0)$ with $(x_1, y_1)$ and $(x_2, y_2)$ -- returns the result that puts $(0,0)$ on the desired side of the line through $(x_1, y_1)$ and $(x_2, y_2).$This last call to
orientationwill use $(x_1, y_1)$ and $(x_2, y_2)$ as the first two arguments (in one order or the other) and $(0,0)$ as the third argument, so it will setvalto either$$(y_1 - y_2) x_1 - (x_1 - x_2) y_1$$
or the exact opposite of that quantity (changing the sign), and it will reliably always set
valto the same sign for every example where the line through $(x_1, y_1)$ and $(x_2, y_2)$ intersects the positive $x$ axis. Which sign that is just depends on the order in which it receives the first two arguments.Since all we need to do is get a consistent sign, we can assume we will compute $(y_1 - y_2) x_1 - (x_1 - x_2) y_1$ rather than the opposite. To find out which sign is the one that says "intersects positive $x$ axis," we just need to work out one example. Let's suppose $(x_1, y_1) = (1, 1)$ and $(x_2, y_2) = (1, -1).$ This is a segment that intersects the positive $x$ axis, and
$$ (y_1 - y_2) x_1 - (x_1 - x_2) y_1 = 2\times 1 - 0 \times 1 = 2. $$
One more detail to figure out. Consider the segment defined by $(x_1, y_1) = (0, 1)$ and $(x_2, y_2) = (0, -1).$ This segment passes through the $x$ axis at $(0,0).$ Do you consider that to be an intersection with "the positive $x$ axis" or not? Note that the algorithm you are currently using will tell you that this segment does intersect the positive $x$ axis; I am merely unsure whether that is the answer you wanted or a defect in the implementation.
So what I would do is to write a function that returned the result
trueif both of the following two conditions are true: