Let's say I had a line with the form: x1, y1, x2, y2
and a given thickness
.
I am looking for a way to convert that line to a rectangle rotated around its origin, such that if you were to draw both of them on a canvas, they would overlap completely.
I've developed a complete reproduction of the problem I'm facing below:
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
const thickness = 7;
const lineX1 = 25, lineY1 = 50;
const lineX2 = 100, lineY2 = 100;
function rotateCanvas(x, y, a) {
ctx.translate(x, y);
ctx.rotate(a);
ctx.translate(-x, -y);
}
function drawRectangle(rX, rY, rW, rH, rA, color) {
ctx.beginPath();
ctx.fillStyle = "#dd3333";
rotateCanvas(rX + rW / 2, rY + rH / 2, rA);
ctx.rect(rX, rY, rW, rH);
rotateCanvas(rX + rW / 2, rY + rH / 2, -rA);
ctx.fill();
}
function drawLine(x1, y1, x2, y2) {
ctx.lineWidth = thickness;
ctx.strokeStyle = "#33dd33";
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.stroke();
}
function calcRectFromLine(x1, y1, x2, y2) {
const dx = x2 - x1;
const dy = y2 - y1;
const mag = Math.sqrt(dx * dx + dy * dy);
const angle = Math.atan2(dy, dx);
return { x: x1, y: y1, w: mag, h: thickness, a: angle };
}
drawLine(lineX1, lineY1, lineX2, lineY2);
const r = calcRectFromLine(lineX1, lineY1, lineX2, lineY2);
drawRectangle(r.x, r.y, r.w, r.h, r.a);
<canvas></canvas>
If you run the code, you'll see that the red rectangle is not on top of the green line. I would like to fix that somehow.
I believe the only function that needs to be fixed is calcRectFromLine
. Ideally that would return a rectangle that, when passed to drawRectangle
, would cause the green line to no longer be visible, as it would be covered completely by the red rectangle.
I also believe I need to use some sort of sin
and cos
to offset the red rectangle, but I'm not sure of the exact math to accomplish that.
You calculate rectangle left and top improperly, using coordinates of rotated line. Correction:
return { x: (x1+x2)/2 - mag/2, y: (y1+y2)/2 - thickness/2,
w: mag, h: thickness, a: angle };`
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
const thickness = 7;
const lineX1 = 25, lineY1 = 50;
const lineX2 = 100, lineY2 = 100;
function rotateCanvas(x, y, a) {
ctx.translate(x, y);
ctx.rotate(a);
ctx.translate(-x, -y);
}
function drawRectangle(rX, rY, rW, rH, rA, color) {
ctx.beginPath();
ctx.fillStyle = "#dd3333";
rotateCanvas(rX + rW / 2, rY + rH / 2, rA);
ctx.rect(rX, rY, rW, rH);
rotateCanvas(rX + rW / 2, rY + rH / 2, -rA);
ctx.fill();
}
function drawLine(x1, y1, x2, y2) {
ctx.lineWidth = thickness;
ctx.strokeStyle = "#33dd33";
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.stroke();
}
function calcRectFromLine(x1, y1, x2, y2) {
const dx = x2 - x1;
const dy = y2 - y1;
const mag = Math.sqrt(dx * dx + dy * dy);
const angle = Math.atan2(dy, dx);
return { x: (x1+x2)/2 - mag/2, y: (y1+y2)/2 - thickness/2, w: mag, h: thickness, a: angle };
}
drawLine(lineX1, lineY1, lineX2, lineY2);
const r = calcRectFromLine(lineX1, lineY1, lineX2, lineY2);
drawRectangle(r.x, r.y, r.w, r.h, r.a);
<canvas><\canvas>