Given two lines, calculate the intersection point, if any
Adapted from How to check if two line segments intersect
Cloned with blockbuilder.org
license: gpl-3.0 | |
border: yes | |
height: 560 | |
scrolling: yes |
Given two lines, calculate the intersection point, if any
Adapted from How to check if two line segments intersect
Cloned with blockbuilder.org
<!doctype html> | |
<html> | |
<head> | |
<meta charset='utf-8'> | |
<title>line intersection demo</title> | |
<style> | |
* { box-sizing: border-box; } | |
body { | |
margin: 0; | |
padding: 10px; | |
} | |
.viz-box { | |
background-color: #efefef; | |
border: 1px solid #aaa; | |
border-radius: 5px; | |
width: calc(100vw - 20px); | |
height: calc(100vh - 20px); | |
margin: auto; | |
overflow: scroll; | |
} | |
</style> | |
</head> | |
<body> | |
<div class="viz-box"></div> | |
<script src='https://d3js.org/d3.v4.min.js'></script> | |
<script> | |
var vizBox = d3.select('.viz-box'), | |
vizDimensions = vizBox.node().getBoundingClientRect(), | |
svgWidth = vizDimensions.width, | |
ctrX = svgWidth * 0.5, | |
svgHeight = vizDimensions.height, | |
ctrY = svgHeight * 0.5, | |
colors = [ | |
'hsl-341', 'hsl-359', 'hsl-18', 'hsl-35', 'hsl-52', | |
'hsl-83', 'hsl-127', 'hsl-160', 'hsl-190', 'hsl-212', | |
'hsl-227', 'hsl-242', 'hsl-259', 'hsl-273', 'hsl-296' | |
], | |
svg = vizBox.append('svg') | |
.attr('width', svgWidth) | |
.attr('height', svgHeight), | |
leftX = 50, | |
rightX = svgWidth - 50, | |
topY = 50, | |
bottomY = svgHeight - 50, | |
marginArgs = [ | |
{ id: 'top', x1: leftX, y1: topY, x2: rightX, y2: topY }, | |
{ id: 'right', x1: rightX, y1: topY, x2: rightX, y2: bottomY }, | |
{ id: 'bottom', x1: leftX, y1: bottomY, x2: rightX, y2: bottomY }, | |
{ id: 'left', x1: leftX, y1: topY, x2: leftX, y2: bottomY} | |
], | |
margins = [], | |
offset = 270, // make first color line vertical | |
increment = 360 / colors.length; | |
marginArgs.forEach(function(margin) { | |
margins.push( | |
svg.append('line') | |
.attr('id', 'margin-' + margin.id) | |
.attr('x1', margin.x1) | |
.attr('y1', margin.y1) | |
.attr('x2', margin.x2) | |
.attr('y2', margin.y2) | |
.attr('stroke', '#aaa') | |
) | |
}); | |
colors.forEach(function(color, clx) { | |
var degrees, radians, x2, y2, bgLine, | |
mgx = 0, | |
mgLen = margins.length, | |
hsl = color.replace( '-', '(' ) + ', 100%, 50%)'; | |
degrees = offset + (increment * clx); | |
radians = degrees * ( Math.PI / 180 ); | |
x2 = ctrX + (svgWidth * Math.cos(radians)) | |
y2 = ctrY + (svgWidth * Math.sin(radians)) | |
bgLine = svg.append('line') | |
.attr('id', 'bgline-' + color) | |
.attr('x1', ctrX.toFixed(2)) | |
.attr('y1', ctrY.toFixed(2)) | |
.attr('x2', x2.toFixed(2)) | |
.attr('y2', y2.toFixed(2)) | |
.attr('stroke', '#ddd'); | |
for (mgx; mgx < mgLen; mgx += 1) { | |
intersects = getIntersects(margins[mgx], bgLine); | |
if (intersects.x && intersects.y && intersects.onLineA && intersects.onLineB) { | |
svg.append('line') | |
.attr('id', 'line-' + color) | |
.attr('x1', ctrX.toFixed(2)) | |
.attr('y1', ctrY.toFixed(2)) | |
.attr('x2', intersects.x.toFixed(2)) | |
.attr('y2', intersects.y.toFixed(2)) | |
.attr('stroke', hsl) | |
.attr('stroke-width', 1.5); | |
svg.append('circle') | |
.attr('id', 'circ-' + color) | |
.attr('cx', intersects.x.toFixed(2)) | |
.attr('cy', intersects.y.toFixed(2)) | |
.attr('r', 5) | |
.attr('fill', hsl); | |
break; | |
} | |
} | |
}); | |
function getIntersects(lineA, lineB) { | |
// if the lines intersect, | |
// var 'intersect' contains the x and y of the intersection (treating the lines as infinite) | |
// and booleans for whether line segment A or line segment B contain the point | |
// adapted from https://martin-thoma.com/how-to-check-if-two-line-segments-intersect/ | |
var a, b, numeratorA, numeratorB, denominator, | |
lineAx1 = +lineA.attr('x1'), | |
lineAy1 = +lineA.attr('y1'), | |
lineAx2 = +lineA.attr('x2'), | |
lineAy2 = +lineA.attr('y2'), | |
lineBx1 = +lineB.attr('x1'), | |
lineBy1 = +lineB.attr('y1'), | |
lineBx2 = +lineB.attr('x2'), | |
lineBy2 = +lineB.attr('y2'), | |
intersect = { x: null, y: null, onLineA: false, onLineB: false }; | |
denominator = ((lineBy2 - lineBy1) * (lineAx2 - lineAx1)) - ((lineBx2 - lineBx1) * (lineAy2 - lineAy1)); | |
if (denominator == 0) { return intersect; } | |
a = lineAy1 - lineBy1; | |
b = lineAx1 - lineBx1; | |
numeratorA = ((lineBx2 - lineBx1) * a) - ((lineBy2 - lineBy1) * b); | |
numeratorB = ((lineAx2 - lineAx1) * a) - ((lineAy2 - lineAy1) * b); | |
a = numeratorA / denominator; | |
b = numeratorB / denominator; | |
// if we cast these lines infinitely in both directions, they intersect here: | |
intersect.x = lineAx1 + (a * (lineAx2 - lineAx1)); | |
intersect.y = lineAy1 + (a * (lineAy2 - lineAy1)); | |
// it is worth noting that this should be the same as: | |
// x = lineBx1 + (b * (lineBx2 - lineBx1)); | |
// y = lineBx1 + (b * (lineBy2 - lineBy1)); | |
// if lineA is a segment and lineB is infinite, they intersect if: | |
if (a > 0 && a < 1) { | |
intersect.onLineA = true; | |
} | |
// if lineB is a segment and lineA is infinite, they intersect if: | |
if (b > 0 && b < 1) { | |
intersect.onLineB = true; | |
} | |
// if line1 and line2 are segments, they intersect if both of the above are true | |
return intersect; | |
} | |
</script> | |
</body> | |
</html> |