1

I can quite easily calculate the point of intersection given two lines. If I start with two vertices:

(x1,y1)
(x2,y2)

I can calculate the slope by doing (y1-y2)/(x1-x2), and then calculating the intercept

y1 - slope * x1

Then do that again, so I have to sets of slope and intercept, then just do:

x = (intercept2 - intercept1) / (slope1 - slope2)
y = slope1 * x + intercept1
(disclaimer: this might not even work, but i've gotten something very close to it to work, and it illustrates my general technique)

BUT that only works with data types with decimals, or non integral. Say the vertices are:

(0,1)
(10,2)

To calculate the slope would result in (1-2)/(0-10), which is -1/-10 which is not 1/10, it is 0.

How can I get code that yields a valid result using only integers?

Edit: I can't use floats AT ALL!. No casting, no nothing. Also, values are capped at 65535. And everything is unsigned.

graham.reeds
  • 16,230
  • 17
  • 74
  • 137
BWG
  • 2,238
  • 1
  • 20
  • 32
  • 1
    Cast your integers to floats, divide, round, cast back to int. – ApproachingDarknessFish Jan 20 '14 at 00:12
  • @ValekHalfHeart I would, but I can't use floats AT ALL. I'm doing this on my graphing calculator, so no floats. – BWG Jan 20 '14 at 00:13
  • 1
    What's a valid result? In integer arithmetic, `1/10 == 0` is correct. The only way to represent the slope accurately using integers is to create a rational type with a numerator and denominator (1 and 10 respectively). Otherwise, you're forced to use floating point arithmetic — which is a heap easier than implementing and using rational arithmetic. – Jonathan Leffler Jan 20 '14 at 00:14
  • 6
    @BWG What kind of satanic calculator doesn't support floats? – ApproachingDarknessFish Jan 20 '14 at 00:14
  • So, to clarify: you are given two lines in an xy-plane. You have been told that these lines intersect at a lattice point. Each line is not specified in slope-intercept form, but rather, as two points that it passes through, which are also lattice points. You want to find the intersection. Is that all correct? – ruakh Jan 20 '14 at 00:14
  • @ruakh But to specify two lines one needs 4 points... – Joker_vD Jan 20 '14 at 00:16
  • @ValekHalfHeart Its complex, but I found a compiler compiles to assembly programs. No floats though, the calc implements them in software, which isn't available through the compiler – BWG Jan 20 '14 at 00:16
  • @ruakh Yes. What is a lattice point? And unless they are parallel, they intersect somewhere. – BWG Jan 20 '14 at 00:17
  • 2
    @BWG Multiply all numbers by 10 (or 100), do the calculations, then divide the result by 10 (or 100, or whatever scaling factor you've chosen). – Joker_vD Jan 20 '14 at 00:17
  • @JonathanLeffler A valid result means that the end result point (intersection) is roughly where it should be. – BWG Jan 20 '14 at 00:18
  • 4
    "And everything is unsigned" -- this restriction will make things interesting. – jedwards Jan 20 '14 at 00:19
  • @Joker_vD: Yes, exactly: two points per line. (I don't think my comment was at all confusing in that respect, but just in case, I've now tweaked it to explicitly say "each line is" instead of "these lines are".) – ruakh Jan 20 '14 at 00:19
  • @Joker_vD That should work. I do that in other places, I don't know why I didn't think of that. – BWG Jan 20 '14 at 00:20
  • possible duplicate of [Find out if 2 lines intersect](http://stackoverflow.com/questions/14176776/find-out-if-2-lines-intersect) – Oliver Charlesworth Jan 20 '14 at 00:20
  • @BWG: Re: "What is a lattice point?": A point whose coordinates are integers. (It can mean other things in other contexts, but that's its default meaning in this sort of context.) Obviously non-parallel lines in the same Cartesian plane must intersect, but even if you're told they're not parallel, there's no reason to assume they intersect at a lattice point. – ruakh Jan 20 '14 at 00:30
  • @ruakh Okay, thanks for the information. I'm not told anything, but I want the nearest lattice point to the actual intersection. – BWG Jan 20 '14 at 00:34
  • Suppose two lines: Line X (1,1)--(2,2) and Line Y (1,2)--(2,1); what answer do you want in this case? – nodakai Jan 20 '14 at 04:34
  • @nodakai (1,1) or (1,2) or (2,1) or (2,2) – BWG Jan 20 '14 at 05:24
  • All-integer line intersection code from Graphics Gems II: https://webdocs.cs.ualberta.ca/~graphics/books/GraphicsGems/gemsii/xlines.c - no division used, only multiplication. – Graham Toal Apr 28 '20 at 17:12

4 Answers4

3

In high school when subtracting fractions, our teachers taught us to find a common denominator

So 1/4 - 1/6 = 3/12 - 2/12 = 1/12

So do the same with your slopes.

int slope1 = n1 / d1;  // numerator / denominator
int slope2 = n2 / d2;
// All divisions below should have 0 for remainder
int g = gcd( d1, d2 ); // gcd( 4, 6 ) = 2
int d = d1 * d2 / g; // common denominator (12 above)
int n = (d/d1) * n1 - (d/d2) * n2; // (1 in 1/12 above)
// n1/d1 - n2/d2 == n/d

I hope I got that right.

brian beuning
  • 2,836
  • 18
  • 22
  • So I store... the numerator and denominator of my slope in separate values... and then do my math in that way? – BWG Jan 20 '14 at 01:50
  • Notice that it is still basically "scale numbers up, calculate, then scale the result down", but with auto-select for the scaling factor. Maths is great! – Joker_vD Jan 20 '14 at 07:18
0

Hm..
(0,1)
(10,2)
and (y1-y2)/(x1-x2). Well, this is the description of one line, not the intersection of
two lines.
As far as I remember lines are described in the form of x * v with x an skalar and v be a
vector. Then it's
x * (0,1) = v2 and
x * (10, 2) = v2.
therefore the lines only intersect if exactly one solution to both equitions exist,
overlap when there are infinitive numbers of solutions and don't intersect when they are
parallel.
http://www.gamedev.net/topic/647810-intersection-point-of-two-vectors/
explains the calcuclation based on the dot - product.

Peter
  • 1,769
  • 1
  • 14
  • 18
  • I was just using those vertices to illustrate how integers can be imprecise to the point of no return, not to show a full problem. You were correct initially, that is the description of one line. I would have another line to intersect it, but that is not shown in my question. – BWG Jan 20 '14 at 01:46
0

Input: line L passing thru (x1, y1) and (x2, y2), and line M passing thru (X1, Y1) and (X2, Y2)

Output: (x, y) of the intersecting point of two lines L and M

Tell Wolfram Alpha to solve y = (y1-y2)/(x1-x2)*(x-x1)+y1 and y = (Y1-Y2)/(X1-X2)*(x-X1)+Y1 for x, y to get this solution:

But I have no idea on how to write a program to implement the above solution for your calculator with only uint16_t ALU.

nodakai
  • 7,773
  • 3
  • 30
  • 60
  • Well actually that could work very well. Since division is the last step to occur, there should be no loss of precision. – BWG Jan 20 '14 at 05:27
0

Thanks to Graham Toal's answer, below is a primitive Rust implementation of the linked C code in their answer, modified to return the point of intersection for the complete line, as opposed to the line segment. It doesn't use much Rust-specific magic so should be reasonably easy to port to other languages.

The function returns a Point where the Lines intersect, if at all, and a flag denoting whether the intersection point lies on both intersected lines (true) or not (false).

/// 2D integer point
struct Point {
    /// The x coordinate.
    pub x: i32,

    /// The y coordinate.
    pub y: i32,
}

/// Line primitive
struct Line {
    /// Start point
    pub start: Point,

    /// End point
    pub end: Point,
}

/// Check signs of two signed numbers
///
/// Fastest ASM output compared to other methods. See: https://godbolt.org/z/zVx9cD
fn same_signs(a: i32, b: i32) -> bool {
    a ^ b >= 0
}

/// Integer-only line segment intersection
///
/// If the point lies on both line segments, the second tuple argument will return `true`.
///
/// Inspired from https://stackoverflow.com/a/61485959/383609, which links to
/// https://webdocs.cs.ualberta.ca/~graphics/books/GraphicsGems/gemsii/xlines.c
fn intersection(l1: &Line, l2: &Line) -> Option<(Point, bool)> {
    let Point { x: x1, y: y1 } = l1.start;
    let Point { x: x2, y: y2 } = l1.end;
    let Point { x: x3, y: y3 } = l2.start;
    let Point { x: x4, y: y4 } = l2.end;

    // First line coefficients where "a1 x  +  b1 y  +  c1  =  0"
    let a1 = y2 - y1;
    let b1 = x1 - x2;
    let c1 = x2 * y1 - x1 * y2;

    // Second line coefficients
    let a2 = y4 - y3;
    let b2 = x3 - x4;
    let c2 = x4 * y3 - x3 * y4;

    let denom = a1 * b2 - a2 * b1;

    // Lines are colinear
    if denom == 0 {
        return None;
    }

    // Compute sign values
    let r3 = a1 * x3 + b1 * y3 + c1;
    let r4 = a1 * x4 + b1 * y4 + c1;

    // Sign values for second line
    let r1 = a2 * x1 + b2 * y1 + c2;
    let r2 = a2 * x2 + b2 * y2 + c2;

    // Flag denoting whether intersection point is on passed line segments. If this is false,
    // the intersection occurs somewhere along the two mathematical, infinite lines instead.
    //
    // Check signs of r3 and r4.  If both point 3 and point 4 lie on same side of line 1, the
    // line segments do not intersect.
    //
    // Check signs of r1 and r2.  If both point 1 and point 2 lie on same side of second line
    // segment, the line segments do not intersect.
    let is_on_segments = (r3 != 0 && r4 != 0 && same_signs(r3, r4))
        || (r1 != 0 && r2 != 0 && same_signs(r1, r2));

    // If we got here, line segments intersect. Compute intersection point using method similar
    // to that described here: http://paulbourke.net/geometry/pointlineplane/#i2l

    // The denom/2 is to get rounding instead of truncating. It is added or subtracted to the
    // numerator, depending upon the sign of the numerator.
    let offset = if denom < 0 { -denom / 2 } else { denom / 2 };

    let num = b1 * c2 - b2 * c1;
    let x = if num < 0 { num - offset } else { num + offset } / denom;

    let num = a2 * c1 - a1 * c2;
    let y = if num < 0 { num - offset } else { num + offset } / denom;

    Some((Point::new(x, y), is_on_segments))
}
Bojangles
  • 99,427
  • 50
  • 170
  • 208