Calculating the Intersection of 2 SVG Lines

The SVG coordinate system is complex.  In order to explain it, I shall start with simplified examples, then progressively increase the sophistication of the intersection algorithm, in ensuing posts, with more working demos on CodePen.

svg lines intersecting
Click on image to view SVG code

The functional ability to remove selected line segments at desired intersections has been missing in XVG (a graphic design tool I’m developing).

To remedy this, I am going to start by demonstrating how to algebraically calculate the exact intersection point of 2 (non-vertical, non-horizontal, and intersecting) SVG lines.

Subsequent posts will demo JS code that implements “find intersection” and “remove line segments” logic in a generalized manner. Then I will complete the job by writing code that replaces a single SVG line with its “intersection split” equivalent (i.e, creating a gap in the segment between where the line intersects with 2 other lines).

Here are the two lines we are going to study in some detail in this post:

line a (red): x1=”20″ y1=”85″ x2=”55″ y2=”40″

line b (black): x1=”15″ y1=”25″ x2=”65″ y2=”95″

Now here comes the tricky part.

An SVG element has an inverted Cartesian coordinate system, which is different from the classic x/y +- quadrants many of us learned in High School geometry.

Instead, y=”0″ defines the vertical origin at the top of an SVG workspace; the SVG y-axis increments from 0 to ∞,  as it extends down vertically.

This is typical in graphics programming, partly owing to an accident of computer history: early CRTs, for example, had scan guns that swiped each line left to right, successively from top to bottom, when refreshing a screen.1

What is an <svg> element?

It’s the layout of the surface (in the form of an invisible rectangle or square) where SVG shapes are going to be contained.

Per Mozilla’s documentation:

The SVG element is a container that defines a new coordinate system and viewport. [My ital.] It is used as the outermost element of SVG documents, but it can also be used to embed an SVG fragment inside an SVG or HTML document.”

To keep things as simple as possible in our example, our SVG elements viewbox=”0 0 100 100”, and its x and y origin attributes are “0”.  This means that any negative x values would be rendered offscreen. For instance, Line 5 is not visible in the viewport as defined in our current example:

<line stroke="brown" stroke-width="1" x1="-100" y1="0" x2="-100" y2="100" id="line5">
<title>Line 5</title>
</line>

In this simplified example, we start counting from the top left corner (0,0), with x increasing from left to right, and y incrementing on the way down to the bottom of the screen, potentially to infinity.

Given that the height of the SVG workspace element that contains these lines is “100″, we will convert y values to “traditional” Cartesian y-coordinates (in order to simplify our application of geometry math) as follows:

(height of SVG container) – (SVG y-coordinate of some point) = (the point’s y-coordinate in standard coordinate geometry)

Thus,

line a (red), can be redefined as follows, in the normal Cartesian units we learned in school:

x1=”20″ y1=”15″

x2=”55″ y2=”60″ (used in verification below)

line b (black):

x1=”15″ y1=”75″

x2=”65″ y2=”5″

Now we will calculate line a’s slope m:

m= 60 – 15 / 55 – 20 = 45 / 35 = 1.28571428571

or m = 15 – 60 / 20 – 55 = – 45 / -35 = 1.28~

Now we can calculate the y-intercept of line a, using by figuring out line a’s point-slope equation:

y – y1 = m(x – x1

y – 15 = 1.28571428571 (x – 20)

y – 15 = 1.28~x – (1.28 * 20)

y – 15 = 1.28~x – 25.6

y = 1.28~x + 15 – 25.6

y = 1.28~x – 10.6

where ~ represents the truncated 9 decimal points

Verifying against line a’s point 2:

1.28571428571 (55) – 10.6 = 60.114285714

Q.E.D

Now let’s again figure it out, using the slope-intercept form equation:

y = mx + b

y = 1.28571428571x + b

15 = 1.28571428571(20) + b

15 = 25.7142857142 + b

b= 15 – 25.7142857142 = -10.7142857142

Verify

y = (1.28571428571 * 55) – 10.7142857142

y = 59.9999999998

Q.E.D

Now let’s do the same for line b:

 

m = 5 – 75 / 65 – 15 = -1.4

75 = –1.4(15) + b

75 = -21 + b

b = 96

Verifying

y = (1.4 * 65) + 96 = 5

Q.E.D

Now let’s find the intersection of both lines:

(1.28571428571 * x) – 10.7142857142 = (-1.4 * x) + 96

1.28571428571x + 1.4x = 10.7142857142 + 96

2.68571428571 x = 106.714285714

x = 106.714285714 / 2.68571428571 = 39.7340425531

Now find the y value

y = (1.28571428571 * 39.7340425531 ) – 10.7142857142

y = (1.28571428571 * 39.7340425531 ) – 10.7142857142

y = 40.3723404253

Now convert y to SVG units:

y_SVG = 100 – 40.3723404253 = 59.6276595747

So the intersection point in SVG units is:

39.7340425531, 59.6276595747

now let us verify this by creating another line that ends at this intersection point (rounded up).

line c (purple): x1=”0” y1=”100” x2=”40” y2=”60

Q.E.D

We now have a set of simple steps that can be turned into JS code to automatically calculate the intersection points of SVG lines.   Note that the algorithm presented here presume that the origin of the SVG viewport remains fixed at 0,0:  as mentioned earlier, we’re not accounting in this post for possible negative x values.  

1Bellamy-Royds et al, Using SVG with CSS3 & HTML5, p. 258