I recently made a “reverse” screenX / Y for processing in this thread. I did try to convert it to p5.js, but was unsuccessful in my first attempts (I really don’t get js class quirky syntax. And now the code link is gone in the first post) You’re welcome to try and convert it if you like.
Whether or not it works might still depend on how you do the collision detection I guess.
Slightly changed version here (processing sketch), demo:
/* Reverse matrix transformation tests
2019.05.05 raron
TODO:
Shear X / Y
Scale
*/
// mouse clicks make a test point that follows the following matrix "level"
final int testPointAtLevel = 2; // zero-based
// Number of Matrix transforms (push/pop "levels")
final int levels = 3;
// Object to keep track of matrix transforms
MatrixTracker2D matrix = new MatrixTracker2D();
// Test figure, to show matrix transforms
TestFigure figureTest[] = new TestFigure[levels];
// Just the test point initial coordinates
float tpx = 15;
float tpy = 20;
void setup() {
// test figures
figureTest[0] = new TestFigure( 300, 300, 0, 0, 50, 100, 0, 0.01);
figureTest[1] = new TestFigure( 200, 0, 0, 0, 25, 50, 0, 0.02);
figureTest[2] = new TestFigure( 50, 50, -10, 20, 25, 10, 0, 0.015);
//figureTest[3] = new TestFigure( 25, -25, 20, 10, 0, 0.03);
size(600, 600);
ellipseMode(RADIUS);
}
void draw() {
background(128);
fill(255);
// Testing a few matrix push/pop levels
for(int i=0; i<levels; i++) {
stroke(0);
strokeWeight(1);
// track a new matrix (save old)
matrix.push();
// transform new current matrix
matrix.move(figureTest[i].x, figureTest[i].y);
matrix.turn(figureTest[i].ang);
// Indicate a matrix "level" with a figure
figureTest[i].display();
figureTest[i].update();
// Test point that follows a figure (matrix)
if (testPointAtLevel == i) testPoint();
// Unrelated test: Ellipsoid line towards mouse pointer
if (mousePressed) testLine(i);
//printMatrixInfo(1);
}
// remove old matrix transforms before new frame
for (int i=0; i<levels; i++) {
matrix.pop();
}
}
void printMatrixInfo(int i) {
println(matrix.txList.get(i), matrix.tyList.get(i), matrix.angList.get(i));
}
// Mouse click makes a point that follows current "level" of matrix transforms
void testPoint() {
if (mousePressed) {
tpx = matrix.posX(mouseX, mouseY); // reverse screenX
tpy = matrix.posY(mouseX, mouseY); // reverse screenY
}
strokeWeight(3);
stroke(#FF0000);
point(tpx, tpy);
}
// A line as from center of an ellipse towards the mouse pointer (just because)
void testLine(int i) {
matrix.push();
matrix.move(figureTest[i].xt, figureTest[i].yt); // testing off-center ellipses
// Turn towards mouse pointer
float mAng = matrix.getAngle(mouseX, mouseY, 0, 0);
matrix.turn(mAng);
// Ellipse radius at angle mAng (pointing at mouse pointer)
float ra = figureTest[i].ra;
float rb = figureTest[i].rb;
float radiusAtAngle = (ra*rb)/sqrt(pow(ra*sin(mAng),2) + pow(rb*cos(mAng),2));
strokeWeight(3);
stroke(#FF0000); // red line inside ellipse
line(0,0,radiusAtAngle,0);
strokeWeight(1);
stroke(#0000FF); // black line outside ellipse
line(radiusAtAngle,0,200,0);
matrix.pop();
}
// Test figure class, to show matrix transforms and rotations
class TestFigure {
float x, y; // x, y matrix translation
float xt, yt; // x, y additional offset
float ra, rb; // radius A and B (of figure)
float ang; // angle
float turnSpeed;
TestFigure( float ex, float ey, float ext, float eyt,
float era, float erb, float angle, float ts) {
x = ex;
y = ey;
xt = ext;
yt = eyt;
ra = era;
rb = erb;
ang = angle;
turnSpeed = ts;
}
void display() {
// Draw around offset from wherever origo (of matrix) is
//ellipse(xt, yt, ra, rb);
rect(xt-ra, yt-rb, 2*ra, 2*rb);
}
void update() {
ang += turnSpeed;
}
}
And the class:
/** Class to keep track of 2D matrix transformations
(to reverse-transform screen coordinates to matrix coordinates)
To keep track of matrix transformations:
Instead of: Use:
-------------- -----------------------------
pushMatrix() MatrixTracker2D.push()
popMatrix() MatrixTracker2D.pop()
resetMatrix() MatrixTracker2D.reset()
translate(x,y) MatrixTracker2D.move(x,y)
rotate(angle) MatrixTracker2D.turn(angle)
Where "MatrixTracker2D" is an object of that type.
To get a transformed position from a screen position (reverse of screenX / screenY):
MatrixTracker2D.posX(x,y)
MatrixTracker2D.posY(x,y) where x,y = screen coordinates
To get the angle between a transformed screen position
and an already transformed position, relative to the matrix X-axis, use:
MatrixTracker2D.getAngle(sx, sy, mx, my)
where:
sx, sy is a screen position, and
mx, my is a position in the current matrix
2019.05.05 raron - First version
(No guarantee that it actually works as intended)
*/
class MatrixTracker2D {
int level = 0;
// Processing allows a maximum of 32 pushMatrix()'es afaik
// I'm including the "base" matrix here, totalling 33.
final int max = 33;
FloatList txList;
FloatList tyList;
FloatList angList;
MatrixTracker2D() {
// pre-allocating max matrix transformations
txList = new FloatList(max);
tyList = new FloatList(max);
angList = new FloatList(max);
// initialize one entry for the "base" matrix (assumed reset)
txList.append(0);
tyList.append(0);
angList.append(0);
level = txList.size(); // is 1 at instantiation
}
// Make space for new matrix transform data
void push() {
if (level>0 && level<max) {
int i = level-1;
txList.append(txList.get(i));
tyList.append(tyList.get(i));
angList.append(angList.get(i));
level = txList.size();
pushMatrix();
}
}
// Translate matrix
void move(float x, float y) {
if (level > 0) {
int i = level-1;
float tempX = txList.get(i);
float tempY = tyList.get(i);
float ang = angList.get(i);
txList.set(i, tempX + x*cos(ang) + y*cos(ang+PI/2));
tyList.set(i, tempY + x*sin(ang) + y*sin(ang+PI/2));
translate(x,y);
}
}
// Rotate matrix
void turn(float angle) {
if (level > 0) {
int i = level-1;
angList.set(i, angList.get(i) + angle);
rotate(angle);
}
}
void reset() {
txList.set(level-1, 0);
tyList.set(level-1, 0);
angList.set(level-1, 0);
resetMatrix();
}
// remove last matrix and data
void pop() {
if (level>0) {
txList.remove(level-1);
tyList.remove(level-1);
angList.remove(level-1);
level = txList.size();
popMatrix();
}
}
// Get matrix X position from screen position
// (reverse screenX)
float posX(float x, float y) {
int i = level-1;
float tx = txList.get(i);
float ty = tyList.get(i);
float ang = atan2(y-ty, x-tx) - angList.get(i);
float pDist = sqrt(pow(x-tx,2) + pow(y-ty,2));
float mx = pDist * cos(ang);
return mx;
}
// Get matrix Y position from screen position
// (reverse screenY)
float posY(float x, float y) {
int i = level-1;
float tx = txList.get(i);
float ty = tyList.get(i);
float ang = atan2(y-ty, x-tx) - angList.get(i);
float pDist = sqrt(pow(x-tx,2) + pow(y-ty,2));
float my = pDist * sin(ang);
return my;
}
// Angle of line between a transformed screen position and
//a matrix position relative to the matrix X-axis.
float getAngle(float sx, float sy, float mx, float my) {
int i = level-1;
float tx = screenX(mx, my);
float ty = screenY(mx, my);
float ang = atan2(sy-ty, sx-tx) - angList.get(i);
// Also works (slower?)
// float tx = posX(sx, sy);
// float ty = posY(sx, sy);
// float ang = atan2(ty-my, tx-mx);
return ang;
}
}