Again, the Y Flip Conundrum

Okay, I know flipping the Y axis has been addressed before (https://forum.processing.org/one/topic/invert-coordinates.html) and I can make shapes just where I want them when I use
scale(1, -1);
translate(0, -height);

in draw(), but I can't figure out how to make the coordinates match in the mousePressed() function so that I can click on areas specified by mathematical rather than "computer" coordinates.

This is, of course, part of the continual conundrum we intro level teachers face as we try to show learners without great math skills that programming is do-able and even fun: is the code to invert the Y axis unobtrusive enough so that we can use the coordinate system my students (kind of) already know or must I teach them "computer coordinates" which are the undoing of half of what my math colleagues have labored to teach them?

[Apologies: frustrated rant to follow]

In creating his brilliant Python Graphics module, John Zelle included a function which transforms coordinates (any way you want) for an entire program with just a single, short line of code you put in at the start. Now I know Python is not a great language for writing video games, but this graphics module nonetheless demands consideration by all teachers of "diverse learners" because you don't have to work against what students have already struggled to learn, i.e. - that Y 'moves' upwards positively and downwards negatively. At the start of every class you don't have to remind them how computers do it differently. You don't have to double the number of vectors students are storing in memory. You don't have to send them off to their math classes or state exams with inverted directions rattling around in their brains. (With graduations now pinned to ever more finicky standardized exams, this is not a small thing.) IF PROCESSING IS SUCH A WONDROUS TEACHING LANGUAGE, HOW ON EARTH COULD SOMEONE NEGLECT TO INCLUDE A SIMILAR COORDINATE SETTING FUNCTION?

[Apologies once more; question resumes]

So, I've seen that perhaps a solution exists using pushMatrix() and popMatrix(), but I haven't been able to make that work. Additionally, I can probably leave my students unconfused by a couple of instances of scale() and translate(), but adding pushMatrix() and popMatrix() with indented code nested between them probably adds more distraction than teaching them the inverted Y concept.

Can anyone share code for aligning inverted Y coordinates across draw() and mousePressed()? With much respect and hope that the misunderstanding is mine, Brooklev

Answers

  • with all due respect, Sir, in all computer languages the coord has its origin in the upper left corner.

    So the kids should just get used to it.

    The answer to your question - or a work around - is screenX() and screenY()

    it let's you store the coords and work with them in mousePressed()

    https://forum.processing.org/two/discussion/6309/how-to-get-my-2d-position-on-the-screen-from-a-3d-model

    other way

    the other way is height - y and apply this on your graph and on the mouse: lastMX, lastMY

    float lastMX, lastMY; 
    
    void setup() {
    
      size(600, 500);
      background(255);
      // noCursor();
    }
    
    void draw() {
    
      background(255);
    
      lastMX=mouseX; 
      lastMY=height-mouseY;
    
      // graph
      for (int x=0; x<width; x++) {
        float y = 2 * x + 9;
        coord ( x, y) ;
        if ((x+3)%11==0) {
          fill(0); 
          text(x+","+y, x+7, height-y);
        }
      }//for
    }
    
    void coord (float x, float y) {
      stroke(0, 255, 0);
      point(x, height-y);
      ellipse(x, height-y, 4, 4);
    }
    
    void mousePressed() {
      println(lastMX, lastMY) ;
    }
    
  • simplified version of the first approach with screenX,screenY

    void setup() {
      size(600, 400);
    }
    
    
    void draw() {
      background(0);
    
      pushMatrix();
      translate(width/2, height/2);
      // scale(90);
      rotate(.6);
      noFill();
      stroke(0, 255, 0);
      ellipse(0, 0, 6, 6);
      float px = screenX(.5, .5);
      float py = screenY(.5, .5);
      popMatrix();
    
      // use px,py
      stroke(255);
      line(0, 0, px, py);
    }
    
  • Hooray Chrisir! You've done it again! Thanks so much for your attention and suggestions. The solution came not from screenX() but from the variable that continuously inverts the mouseY value in draw() so that mouse clicks can be tested with math coordinates rather than computer coordinates. This is simple and elegant (and something I really should have figured out for myself) and shows yet again how reliant I am upon this community of good hearted Processing experts.

    While this technique would probably snarl a complex program, it's exactly what I need to make a simple "animation machine" for my students to customize, a bare bones video game in which to implement the rudimentary logical operations they need to master. (code at bottom of post) With the inversion handled by only 4 easily dismissed lines in 1 place, the machine now functions transparently with code that is simple to modify and expand with no perplexing screenX() or pushMatrix() to copy and wonder about.

    With absolutely all respect, I would add a few hypotheses:

    1. OpenGL is a widely employed language that does not use an origin in the upper left corner. Am I correct in this understanding?

    2. The entire reason for having the origin in the upper left (saving video card processing while writing to CRT monitors) has been obviated by modern chip speeds. The upper left corner origin may thus be an example of technological lockin akin to the QWERTY keyboard.

    3. Many examples of techno lockin (like the QWERTY keyboard) are harmless and charming, but the upper left origin actively dilutes a vital principle that is continuously taught elsewhere.

    4. If these first 3 ideas hold water, then we must consider computer science clinging to the upper left origin to be a kind of vanity of the discipline, the adjustment to which is merely a rite of passage.

    5. The population of people learning programming has expanded so much today, that we must recognize that not everyone who is taught programming will learn to program at a skill level that most folks in this forum would recognize. Whether we like it or not, Processing is assuming an important place in rudimentary programming instruction, an activity that will only grow. I'm finding Processing to be the bridge between Scratch and a multipurpose language like Python or some form of C.
      Why do we care how people who may never be programmers learn programming? Just look to music instruction in the schools: not everyone who takes a required music class is going to be able to play recognizable music, but everyone still deserves the opportunity to learn some basic things about music. Now imagine that in a required music class you were taught that "high" tones are notated at the bottom of the musical staff and "low" tones at the top. This contradicts a lot that you learn elsewhere and, yes, you could make the adjustment, but it is certainly a less than ideal situation that should be remedied if possible.

    Thanks again to Chrisir. I'm sorry I must have mis-posted this as a discussion rather than a question because you definitely deserve the big SOLVED shout out. Another big shout out to anyone who has actually read this far. (Maybe this is correctly posted as a discussion after all? I look forward to learning anyone else's thoughts on this subject!)

    As mentioned, here's the code for my animation machine. If there are any glitches or if it is all going to fall apart in ways I have not foreseen, I'd be supremely grateful for your feedback.
    All best, Brooklev

    // This Processing program creates a little animation machine
    // with controls that you can customize.
    
    // First, we need to "declare" a few variables of 3 different types.
    int bDia, cDia, mvX, mvY;
    float cX, cY, clickX, clickY;
    color cCol;
    
    void setup() {
      size(201, 400);  // Create a program window 201 pixels wide and 400 pixels high.
      stroke(127); // Set the color for the outlines of our shapes.
      bDia = 20; // Set the diameter of our circular control buttons.
      cDia = 20; // Set the diameter of the "action circle" we will control.
      cX = 100;  // Set the starting horizontal position of the action circle.
      cY = 300;  // Set the starting vertical position of the action circle.
      cCol = color(255, 255, 255);  // Set the starting color of the action circle.
      mvX = 0;  // Set the horizontal movement of the action circle.
      mvY = 0;  // Set the vertical movement of the action circle.
    }
    
    void draw() {
      // These first 4 lines let you use math coordinates instead of computer coordinates.
      scale(1, -1);
      translate(0, -height);
      clickX = mouseX;
      clickY = height - mouseY;
    
      fill(255); // Color the screen white.
      rect(0, 200, 200, 200);  // Draw the square "action screen".
    
      ellipse(100, 60, bDia, bDia); // Draw the top button.
      ellipse(100, 100, bDia, bDia); // Draw the middle button.
      ellipse(100, 140, bDia, bDia); // Draw the bottom button.
      ellipse(60, 100, bDia, bDia); // Draw the left button.
      ellipse(140, 100, bDia, bDia); // Draw the right button. 
    
      fill(cCol);  // Set the color for the action circle.
      cX = cX + mvX; // Set the horizontal position of the action circle.
      cY = cY + mvY; // Set the vertical position of the action circle.
    
      // The 2 "print lines" below will display at the bottom of this window.
      // They will let us check the coordinates of the program window.
      println("X =", clickX);
      println("Y =", clickY);
    
      ellipse(cX, cY, cDia, cDia); // Draw the action circle.
    }
    
    void mousePressed() {
      //Check if the user clicked the middle button.
      if (dist(clickX, clickY, 100, 100) < bDia/2) {
        cCol = color(255, 0, 0);
        // If so, turn the action circle red.
      }
    
      //Check if the user clicked the top button.
      else if (dist(clickX, clickY, 100, 140) < bDia/2) {
        mvY = 1;
        //If so, make the action circle move upwards.
      }
    }
    
  • if you want to do more to hide the 4 lines of magic, put them into a method and call that from the top of draw. and stick a comment on the method saying THIS IS MAGIC. DO NOT CHANGE.

    a button class would also be a good idea.

  • Thanks koogs! These are good recommendations though they introduce more complex structures. I like being able to explain every line to a beginner, which becomes more difficult if one includes methods and classes. I will weigh your kind advice thoughtfully.

  • I don't have anymore insights

    ;-)

Sign In or Register to comment.