The situation is as followed: I have a rectangular grid. Which has a dot in it. Located at the top left (position: x:1 & y:1). The coordinates from this grid range from 1 to 4. Using a rotate function like described in this question. I am able to rotate this dot according the center point of a rectangular canvas. For this I use (width + 1) /2 and (height + 1)/2. The addition of the number 1 is related to the canvas, and just creates a white margin/offset/border around the rectangular grid where I plot my coordinates to. The dimensions of this canvas range from 0 to 5.
When rotating along a square grid. Everything goes well. But when the width is not equal to its height. The desired outcome is not as intended. It should rotate as a Tetris block. But the "points" of the Tetris block move outside its grid.
Below I have visualized this problem in more depth. The red dot is the point which needs to be rotated. The light blue/green point is the center point which the red dots is being rotated. The rotation is 90 degrees clockwise.
Update: Visualisation of problem
What happens in a square grid
What happens in a rectangular grid
Code snippet
function rotate(cx, cy, x, y, angle) {
var radians = (Math.PI / 180) * -angle,
cos = Math.cos(radians),
sin = Math.sin(radians),
nx = (cos * (x - cx)) + (sin * (y - cy)) + cx,
ny = (cos * (y - cy)) - (sin * (x - cx)) + cy;
return {x:nx, y: ny};
}
rotate((width +1)/2, (height + 1)/2, x,y, 90)
var tempWidth = width;
width = height;
height = tempWidth;
What is the correct way to rotate a grid with its contents 90 degrees.
Update2: Visual code snippet
const svgHelper = {
init: (width, height, scale) => {
const svg = document.createElementNS("http://www.w3.org/2000/svg", 'svg');
svg.setAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink")
svg.setAttribute("x", "0px")
svg.setAttribute("y", "0px")
svg.setAttribute("viewBox", `0 0 ${width + 1} ${height + 1}`)
svg.setAttribute("xml:space", `preserve`)
return svg;
},
addCircle: (element, color, x, y, radius, className) => {
element.insertAdjacentHTML("beforeend", `\r<circle
style="fill: ${color}"
cx="${x}"
cy="${y}"
r="${radius}"
class="${className}"
/>`);
return element.lastChild;
},
addText: (element, string) => {
element.insertAdjacentHTML("beforeend", `\r<text x="0.2" y=".2">${string}</text>`);
return element.lastChild;
}
}
const Grid = {
init: (width, height, margin) => {
const result = {
margin: margin,
array: []
};
for (var i = 0; i < height; i++) {
result.array.push([]);
for (var ii = 0; ii < width; ii++) {
result.array[i].push(0);
}
}
return result.array;
},
draw: (svg) => {
const tmp = svg.getAttribute("viewBox").split(" ");
const width = tmp[2]
const height = tmp[3]
for (var y = 1; y < height; y++) {
for (var x = 1; x < width; x++) {
var posX = x //grid.margin
var posY = y //grid.margin
svgHelper.addCircle(svg, "#eee", posX, posY, .1);
}
}
}
}
const updateGrid = (width, height,element) => {
element.setAttribute("viewBox", `0 0 ${width + 1} ${height + 1}`)
// Remove old points
var points = element.querySelectorAll("circle")
for (var i = 0; i < points.length; i++) {
points[i].remove();
}
Grid.draw(element);
}
function rotate(cx, cy, x, y, angle) {
var radians = (Math.PI / 180) * -angle,
cos = Math.cos(radians),
sin = Math.sin(radians),
nx = (cos * (x - cx)) + (sin * (y - cy)) + cx,
ny = (cos * (y - cy)) - (sin * (x - cx)) + cy;
return {x:nx, y: ny};
}
const draw = (width, height) => {
const div = document.createElement("div");
const element = svgHelper.init(width, height);
const span = document.createElement("span");
div.appendChild(element);
div.appendChild(span);
span.className = "text";
let point = {x:1, y:1};
document.querySelector("body").appendChild(div);
Grid.draw(element);
let prevPoint = svgHelper.addCircle(element, "#f00", point.x, point.y, .125, "point")
setInterval(() => {
var tmpWidth = width;
width = height;
height = tmpWidth;
updateGrid(width, height, element)
point = rotate((width + 1)/2, (height + 1)/2, point.x, point.y, 90)
prevPoint = svgHelper.addCircle(element, "#f00", point.x, point.y, .125, "point")
span.innerText = `x: ${Math.round(point.x)} y: ${Math.round(point.y)}`;
}, 1000)
}
draw(4,4)
draw(1,4)
div {
position: relative;
display: inline-block;
}
svg {
width: 135px;
height: 135px;
background-color: lightgray;
margin: 10px;
}
span {
font-size: 10px;
display: block;
margin-left: 10px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="./index.css">
</head>
<body>
<script src="index.js"></script>
</body>
</html>