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> |