Use angleReflect()
from Geometric.js to calculate the angle of reflection given an angle of incidence and a surface angle.
The blue line represents the angle of incidence, the purple line the angle of reflection, and the black line the surface. You can change the angle of incidence by draggin the blue circle, and the angle of the surface by dragging the black circle.
xxxxxxxxxx
<html>
<head>
<style>
body {
margin: 0;
}
line {
stroke-width: 2px;
pointer-events: none;
}
.surface-line {
stroke: black;
}
.start-angle {
stroke: steelblue;
}
.reflect-angle {
stroke: purple;
}
circle {
stroke: #fff;
cursor: pointer;
}
.start-handle {
fill: steelblue;
}
</style>
</head>
<body>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="https://unpkg.com/geometric@1.0.6/build/geometric.js"></script>
<script>
var width = window.innerWidth, height = window.innerHeight;
var center = [width / 2, height / 2];
var svg = d3.select("body").append("svg").attr("width", width).attr("height", height);
var surfaceAnglePrev = 0,
surfaceAngle = 0,
surfaceAngleChange = 0,
surfaceStartPoint,
surfaceEndPoint,
startAngle = 235,
reflectedAngle,
distance = 200,
startPoint,
reflectedPoint;
var surfaceDragGenerator = d3.drag()
.on("drag", d => {
surfaceAnglePrev = surfaceAngle;
surfaceAngle = geometric.lineAngle([[event.pageX, event.pageY], center]);
surfaceAngleChange = surfaceAngle - surfaceAnglePrev;
update();
});
var surfaceLine = svg.append("line")
.attr("class", "surface-line");
var surfaceHandle = svg.append("circle")
.attr("class", "surface-handle")
.attr("r", 10)
.call(surfaceDragGenerator);
var startDragGenerator = d3.drag()
.on("drag", d => {
startPoint = [event.pageX, event.pageY];
distance = geometric.lineLength([center, startPoint]);
startAngle = geometric.lineAngle([center, startPoint]);
update();
});
var startLine = svg.append("line")
.attr("class", "start-angle")
.attr("x2", center[0])
.attr("y2", center[1]);
var startHandle = svg.append("circle")
.attr("class", "start-handle")
.attr("r", 10)
.call(startDragGenerator)
var reflectedLine = svg.append("line")
.attr("class", "reflect-angle")
.attr("x2", center[0])
.attr("y2", center[1]);
update();
function update(){
surfaceStartPoint = geometric.pointTranslate(center, surfaceAngle, -120);
surfaceEndPoint = geometric.pointTranslate(center, surfaceAngle, 120);
startAngle += surfaceAngleChange;
reflectedAngle = geometric.angleReflect(startAngle - 180, surfaceAngle); // subtract 180 from start angle so that it begins at start point
startPoint = geometric.pointTranslate(center, startAngle, distance);
reflectedPoint = geometric.pointTranslate(center, reflectedAngle, distance);
surfaceLine
.attr("x1", surfaceStartPoint[0])
.attr("y1", surfaceStartPoint[1])
.attr("x2", surfaceEndPoint[0])
.attr("y2", surfaceEndPoint[1]);
surfaceHandle
.attr("transform", "translate(" + surfaceStartPoint + ")");
startLine
.attr("x1", startPoint[0])
.attr("y1", startPoint[1]);
startHandle
.attr("transform", "translate(" + startPoint + ")");
reflectedLine
.attr("x1", reflectedPoint[0])
.attr("y1", reflectedPoint[1]);
}
</script>
</body>
</html>
https://d3js.org/d3.v5.min.js
https://unpkg.com/geometric@1.0.6/build/geometric.js