Ich versuche zu testen, ob ein Punkt innerhalb eines rechteckigen Bereichs ist, der sich um einen Winkel (x, y) dreht, wie im Bild unten. Dies ist sprachunabhängiges Problem, aber ich arbeite jetzt mit HTML5 Canvas.Wie testen, ob ein Punkt in einem rechteckigen Bereich ist, der einen Winkel dreht?
Angenommen, der zu testende Punkt ist (x1, y1), ist die Breite des Rechtecks 100 und die Höhe 60. Im normalen kartesischen Koordinatensystem ist das Rechteck ABCD oben links Punkt A (canvas.width/2, canvas.height/2 -rect.height/2)
. Ich nehme an, dass (canvas.width/2, canvas.height/2)
in der Mitte der Linie AB ist, wo B (canvas.width/2, canvas.height/2 + rect.height /2)
ist.
Ich habe einige Ressourcen here gelesen und schrieb ein Testprojekt, aber es testet nicht den richtigen Bereich. In meinem Testprojekt möchte ich den folgenden Effekt:
Wenn sich die Maus an einem Punkt befindet, der innerhalb des Bereichs des Test-Rechtecks liegt, wird ein Punkt um die Maus herum angezeigt. Wenn es außerhalb des Rechtecks liegt, wird nichts angezeigt.
aber mein Testprojekt wie folgt aussieht: (Beachten Sie, dass, obwohl ich die Vektor-basierte Technik verwendet, um den Punkt in einem gedrehten rechteckigen Bereich zu testen, die Testfläche bleibt das Rechteck vor der Rotation)
// Detecting a point is in a rotated rectangle area
// using vector based method
const canvas = document.getElementById('canvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const ctx = canvas.getContext('2d');
class Rectangle {
\t constructor(x, y, width, height) {
\t this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.searchPoint = { x: 0, y: 0};
this.binding();
}
binding() {
\t let self = this;
window.addEventListener('mousemove', e => {
if (!e) return;
let rect = canvas.getBoundingClientRect();
let mx = e.clientX - rect.left - canvas.clientLeft;
let my = e.clientY - rect.top - canvas.clientTop;
self.searchPoint = { x: mx, y: my };
});
\t }
}
let rect = new Rectangle(canvas.width /2, canvas.height /2 - 30, 100, 60);
function vector(p1, p2) {
return {
x: (p2.x - p1.x),
y: (p2.y - p1.y)
};
}
function point(x, y) {
\t return { x, y };
}
// Vector dot operation
function dot(a, b) {
return a.x * b.x + a.y * b.y;
}
function pointInRect(p, rect, angle) {
\t let a = newPointTurningAngle(0, -rect.height/2, angle);
\t let b = newPointTurningAngle(0, rect.height/2, angle);
let c = newPointTurningAngle(rect.width, rect.height/2, angle);
\t let AB = vector(a, b);
let AM = vector(a, p);
let BC = vector(b, c);
let BM = vector(b, p);
let dotABAM = dot(AB, AM);
let dotABAB = dot(AB, AB);
let dotBCBM = dot(BC, BM);
let dotBCBC = dot(BC, BC);
return 0 <= dotABAM && dotABAM <= dotABAB && 0 <= dotBCBM && dotBCBM <= dotBCBC;
}
function drawLine(x, y) {
\t ctx.strokeStyle = 'black';
\t ctx.lineTo(x, y);
ctx.stroke();
}
function text(text, x, y) {
\t ctx.font = "18px serif";
ctx.fillText(text, x, y);
}
function newPointTurningAngle(nx, ny, angle) {
\t return {
\t x: nx * Math.cos(angle) - ny * Math.sin(angle),
y: nx * Math.sin(angle) + ny * Math.cos(angle)
};
}
function animate() {
\t ctx.clearRect(0, 0, canvas.width, canvas.height);
\t ctx.setTransform(1, 0, 0, 1, 0, 0);
\t ctx.moveTo(canvas.width/2, 0);
drawLine(canvas.width /2, canvas.height/2);
ctx.moveTo(0, canvas.height/2);
drawLine(canvas.width/2, canvas.height /2);
\t let angle = -Math.PI/4;
\t ctx.setTransform(Math.cos(angle), Math.sin(angle), -Math.sin(angle), Math.cos(angle), canvas.width/2, canvas.height/2);
//ctx.setTransform(1, 0, 0, 1, canvas.width/2, canvas.height/2);
\t ctx.strokeStyle = 'red';
ctx.strokeRect(0, -rect.height/2, rect.width, rect.height);
\t let p = newPointTurningAngle(rect.searchPoint.x - canvas.width/2, rect.searchPoint.y - canvas.height/2, angle);
\t let testResult = pointInRect(p, rect, angle);
\t if (testResult) {
\t ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.beginPath();
\t ctx.fillStyle = 'black';
\t ctx.arc(rect.searchPoint.x, rect.searchPoint.y, 5, 0, Math.PI * 2);
ctx.fill();
}
ctx.setTransform(1, 0, 0, 1, 0, 0);
text('searchPoint x: ' + rect.searchPoint.x + ', y: ' + rect.searchPoint.y, 60, 430);
text('x: ' + canvas.width/2 + ', y: ' + canvas.height/2, 60, 480);
requestAnimationFrame(animate);
}
animate();
<canvas id='canvas'></canvas>
Lösung Aktualisiert
ich noch die Vektor-basierte Methode bin wie folgt:
Jetzt habe ich den gedrehten Winkel des Punktes und die Eckpunktkoordinaten geändert, so dass der Punkt im Rechteck erkannt werden kann. Die Eckpunkte befinden sich bereits im gedrehten Koordinatensystem, sodass sie nicht übersetzt werden müssen. Der Punkt der Mausposition muss jedoch übersetzt werden, bevor sie im Rechteckbereich getestet wird.
In setTransform
Verfahren rotierte der Winkel positiv ist, wenn im Uhrzeigersinn gedreht wird, die Form ist:
ctx.setTransform(angle_cosine, angle_sine, -angle_sine, angle_cosine, x, y);
So, wenn der Punkt des neuen Berechnungskoordinaten nach einem Winkel dreht, die Formel, dies ändern muß, so dass der Winkel ist positiv, wenn auch im Uhrzeigersinn gedreht:
new_x = x * angle_cosine + y * angle_sine;
new_y = -x * angle_sine + y * angle_cos;
// Detecting a point is in a rotated rectangle area
// using vector based method
const canvas = document.getElementById('canvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const ctx = canvas.getContext('2d');
class Rectangle {
\t constructor(x, y, width, height) {
\t this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.searchPoint = { x: 0, y: 0};
this.binding();
}
binding() {
\t let self = this;
window.addEventListener('mousemove', e => {
if (!e) return;
let rect = canvas.getBoundingClientRect();
let mx = e.clientX - rect.left - canvas.clientLeft;
let my = e.clientY - rect.top - canvas.clientTop;
self.searchPoint = { x: mx, y: my };
});
\t }
}
let rect = new Rectangle(canvas.width /2, canvas.height /2 - 30, 100, 60);
function vector(p1, p2) {
return {
x: (p2.x - p1.x),
y: (p2.y - p1.y)
};
}
function point(x, y) {
\t return { x, y };
}
// Vector dot operation
function dot(a, b) {
return a.x * b.x + a.y * b.y;
}
function pointInRect(p, rect) {
let a = { x: 0, y: -rect.height/2};
let b = { x: 0, y: rect.height/2};
let c = { x: rect.width, y: rect.height/2};
text('P x: ' + p.x.toFixed() + ', y: ' + p.y.toFixed(), 60, 430);
text('A x: ' + a.x.toFixed() + ', y: ' + a.y.toFixed(), 60, 455);
text('B x: ' + b.x.toFixed() + ', y: ' + b.y.toFixed(), 60, 480);
\t let AB = vector(a, b);
let AM = vector(a, p);
let BC = vector(b, c);
let BM = vector(b, p);
let dotABAM = dot(AB, AM);
let dotABAB = dot(AB, AB);
let dotBCBM = dot(BC, BM);
let dotBCBC = dot(BC, BC);
return 0 <= dotABAM && dotABAM <= dotABAB && 0 <= dotBCBM && dotBCBM <= dotBCBC;
}
function drawLine(x, y) {
\t ctx.strokeStyle = 'black';
\t ctx.lineTo(x, y);
ctx.stroke();
}
function text(text, x, y) {
\t ctx.font = "18px serif";
ctx.fillText(text, x, y);
}
function newPointTurningAngle(nx, ny, angle) {
\t let cos = Math.cos(angle);
let sin = Math.sin(angle);
\t return {
\t x: nx * cos + ny * sin,
y: -nx * sin + ny * cos
};
}
function animate() {
\t ctx.clearRect(0, 0, canvas.width, canvas.height);
\t ctx.setTransform(1, 0, 0, 1, 0, 0);
\t ctx.moveTo(canvas.width/2, 0);
drawLine(canvas.width /2, canvas.height/2);
ctx.moveTo(0, canvas.height/2);
drawLine(canvas.width/2, canvas.height /2);
let angle = - Math.PI/4;
\t ctx.setTransform(Math.cos(angle), Math.sin(angle), -Math.sin(angle), Math.cos(angle), canvas.width/2, canvas.height/2);
\t ctx.strokeStyle = 'red';
ctx.strokeRect(0, -rect.height/2, rect.width, rect.height);
\t let p = newPointTurningAngle(rect.searchPoint.x - canvas.width/2, rect.searchPoint.y - canvas.height/2, angle);
ctx.setTransform(1, 0, 0, 1, 0, 0);
\t let testResult = pointInRect(p, rect);
\t if (testResult) {
ctx.beginPath();
\t ctx.fillStyle = 'black';
\t ctx.arc(rect.searchPoint.x, rect.searchPoint.y, 5, 0, Math.PI * 2);
ctx.fill();
}
ctx.setTransform(1, 0, 0, 1, 0, 0);
text('searchPoint x: ' + rect.searchPoint.x + ', y: ' + rect.searchPoint.y, 60, 412);
text('x: ' + canvas.width/2 + ', y: ' + canvas.height/2, 60, 510);
requestAnimationFrame(animate);
}
animate();
<canvas id='canvas'></canvas>
roate Punkt und Rechteck rückwärts vor der Berechnung? – wutzebaer
@wutzebaer. Drehen Sie entweder den Mauszeiger oder das Rechteck, aber nicht beide. ;-) – markE