Interactive rotating cube. 3D graph paper (with rules)

edited January 2016 in Questions about Code

Hello everyone. I am a beginner to processing. I would like to:

  1. Display a grid of dots. Grid points only. No lines (ex. 90x90)
  2. Allow the user to switch between a 2d and "3D View"
  3. Allow the user to spin, pivot, tilt, rotate the cube using the mouse. (Ex. http://visjs.org/graph3d_examples.html)
  4. Allow the user to zoom in/out using the mouse scroll button. (Ex. http://visjs.org/graph3d_examples.html)
  5. Allow the user to select a dot within in the cube.
  6. Allow the user to left-click on a dot highlighting it (the dot becomes bigger/bold)
  7. Allow the user to select a second dot in the same plane connecting a straight line between them. Allow the user to go on creating lines in a plane until:

  8. The user right-clicks a dot in the selected plane and chooses (perhaps from a pop-up/drop-down menu) "degrees of arc" (45, 90, 135).

  9. Once chosen a straight "arc line" is created between the "arc point" and a landing point in the adjacent plane determined by the angle chosen (i.e 90 degree arc creates a line running along the z axis (perpendicular to the plane) connecting the "arc dot" to the corresponding dot in the above plane (closer to the user). If 45, or 135 degrees the "arc line" will end at one of two points in-between visible grid dots in the above plane.)

  10. The new plane is automatically selected and any further points (left) clicked will create a line similar to step 7 above (snapping to the nearest grid point (45, 90, 135).

Optional:

A control panel may be displayed (perhaps at the bottom of the screen) Where: The user can view/edit the number/color of the highlighted plane. The user can highlight the 45/135 grid points within the cube (smaller than initial 90 degree grid dots) The user can "take back" previous line creation/dot selections.

I have copied code from two examples I found in the forums here and managed the stitch them together to sort of do the job.

Ive managed to get LINES (not dots) drawn and rotate the shape in 3d however it seems like the grid is made up of separate

boxes all being rotated individually. See code below:

// Below - (Added from rotating cube script) 
float rotx = PI/4;
float roty = PI/4;
float rotz = PI/4;
// Above - (Added from rotating cube script) 

void setup() {
  size(500, 500, P3D);
  strokeWeight(.5);
  stroke(0, 0, 0);
}
void draw() {

  background(152);


  for (int x = 0; x <= height/2; x += 50) {
    for (int y = 0; y <= height/2; y += 50) {
      for (int z = 0; z <= height/2; z += 50) {
        pushMatrix();
        translate(height/4 + x, height/4 + y, -125);

        // Below - (Added from rotating cube script) 
        rotateX(rotx);
        rotateY(roty);
        //scale(90);
        // Above - (Added from rotating cube script) 

        fill(255);
        box(150, 150, 150);
        popMatrix();
      }
    }
  }
}
// Below - (Added from rotating cube script) 
void mouseDragged() {
  float rate = 0.01;
  rotx += (pmouseY-mouseY) * rate;
  roty += (mouseX-pmouseX) * rate;
}
// Above - (Added from rotating cube script) 

Any help would be appreciated.

Answers

  • edited October 2015 Answer ✓

    Hey,

    at the moment you apply the rotation to all individual objects. If you want to rotate everything at once, you have to move the rotation-part in front of your for-loops.

    void draw() {
      background(200);
    
      // go to the center
      translate(width/2, height/2 ,-125);
    
      // apply rotation
      rotateX(rotx);
      rotateY(roty);
    
      for (int x = 0; x <= height/2; x += 50) {
        for (int y = 0; y <= height/2; y += 50) {
          for (int z = 0; z <= height/2; z += 50) {
            pushMatrix();
            translate( x-height/4,  y-height/4, z-height/4); 
            point(0,0,0);
            popMatrix();
          }
        }
      }
    }
    
  • Answer ✓

    This is obviously homework.

    Don't try to copy other people's code to get this done. Instead, develop it yourself from scratch. And to do that, start with the first goal:

    1. A grid of dots.

    No lines. No cubes. No 3D. No rotating. Just a grid of dots. Can you attempt that for us, or even get that working? Post your code of it here for more help.

  • @TfGuy44: no home work. I am an IT professional but have 0 professional experience programming (unless you count batch files back in 1991 :))

    This is just my own personal project. I will see if I can create that grid and back to you.

  • edited October 2015

    Finally got a chance to get back to my project :) I managed to create the grid.

    void setup(){
       size(400,400);
       background (255);
       noStroke();
    
    int x = 30;
    int y = 30;
    
      for(int i = 0; i < width/x; i++){
          for(int j = 0; j < height/y; j++){
            pushMatrix();
            translate(i*x, j*y);
            Grid();
            popMatrix();
          }
    }
    }
    
    void Grid(){
    
    pushMatrix ();
    translate (-85,-16);
    smooth();
    scale (0.35);
    fill (0);
    ellipse (275,100,5,5);
    fill (39,155,119,100);
    popMatrix();
    }
    

    Should I try to implement the zoom function before transforming the grid into a 3d cube? And again thanks for any help you can bring.

  • edited October 2015

    Decided to take it one step at a time and get the line function working. I want to have a line drawn on mouse click from the previous mouse click position to the current one. My code is below but all I am getting are dots:

    void draw() {
      strokeWeight(10);
      println("Current saved mouse position: " + savedMouse.x + ", " + savedMouse.y); //Print the saved mouse position
    }
    
     void dusty123(){
    
     }
    void mousePressed() {
      savedMouse.x = mouseX;  //Save the mouse position;
      savedMouse.y = mouseY;
      line(mouseX, mouseY, savedMouse.x, savedMouse.y);
    }
    

    I'm sure I'm missing a basic concept here. Anyone able to point me in the right direction?

  • Try

    line(mouseX, mouseY, pmouseX, pmouseY);

  • Answer ✓

    Pmousex is the previous mouse position

    No need to save it - it gets stored automatically

  • Answer ✓

    Your version maybe would work if you have the line command before the storing of mousex and y

  • Answer ✓

    I suppose you only posted a part of your code, because the is no setup and no variables declared.

    The reason for only getting dots instead of lines is in line 10 and 11: You store the mouse-position in "savedMouse", so the saved mouse-position and the current mouse-position are the same. If you draw the line first and store the mouse-position after that, it should work.

  • edited October 2015

    Sorry everybody for the incomplete code earlier. @Chrisir I tried pmouseX/Y before and kept getting only dots. I took yours and @benja's advice and added the line command before the storage and it worked but it kept drawing a line from the 0,0 position when the code initiated so I added the if statement below:

    PVector savedMouse; //The saved mouse position
    
    void setup() {
      size(400, 400);
      savedMouse = new PVector(0, 0); //Initialize the PVector
    }
    
    void draw() {
      println("Current saved mouse position: " + savedMouse.x + ", " + savedMouse.y); //Print the saved mouse position
    }
    
    void mousePressed() {
     if (savedMouse.x > 0) { 
     line(mouseX, mouseY, savedMouse.x, savedMouse.y);
      }
     savedMouse.x = mouseX;  //Save the mouse position;
     savedMouse.y = mouseY;
    }
    

    Seems to work. Got SO much homework (@TfGuy44 :)) to do. Will be asking a lot more dumb questions later. Thank you all for your help.

  • Answer ✓

    So you did lie to TFGuy44 ?

  • @Chrisir Nope. Just throwing a shot at him :) Created the line -creation-function + 2d grid. Want to add right click menu next:

    PVector savedMouse; //The saved mouse position
    
    void setup() {
      size(400, 400);
      background (255);
      savedMouse = new PVector(0, 0); //Initialize the PVector
    int gx = 30;
    int gy = 30;
    
    
      for(int i = 0; i < width/gx; i++){
          for(int j = 0; j < height/gy; j++){
            pushMatrix();
            translate(i*gx, j*gy);
            Grid();
            popMatrix();
          }
    }
    }
    
    void Grid(){
    
    pushMatrix ();
    translate (-85,-16);
    smooth();
    scale (0.35);
    fill (0);
    ellipse (275,100,5,5);
    fill (39,155,119,100);
    popMatrix();
    }
    void draw() {
      println("Current saved mouse position: " + savedMouse.x + ", " + savedMouse.y); //Print the saved mouse position
    }
    
    void mousePressed() {
     if (mousePressed && (mouseButton == RIGHT)) {
    savedMouse.x = 0;
     }
     if (savedMouse.x > 0) { 
     line(mouseX, mouseY, savedMouse.x, savedMouse.y);
      }
    savedMouse.x = mouseX;  //Save the mouse position;
    savedMouse.y = mouseY;
    }
    
  • Answer ✓

    Your code is all over the place - even the code for your simple grid of dots.

    I don't know why you're trying to draw lines, but the code for that is sort of a mess too.

    Something like this is all I wanted to see first:

    void setup() {
      size(400, 400);
    }
    
    void draw() {
      background(255);
      noStroke();
      fill(0);
      for (int x = 10; x < width; x+=10) {
        for (int y = 10; y < height; y+=10) {
          ellipse(x, y, 4, 4);
        }
      }
    }
    

    Look at how simple and straight-forward this is. It draws a grid of dots. That's all.

  • Answer ✓

    Step two would be to add a "2D view" and a "3D view". To do this, your program would need some information about which one of the two possible states it is in. Here, I accomplish this by adding a boolean variable, is_3d, that is true when we are looking at the 3D view. Also notice that the sketch is now a 3D sketch.

    boolean is_3d;
    
    void setup() {
      size(400, 400, P3D);
      smooth();
      is_3d = false;
    }
    
    void draw() {
      if (is_3d) {
        background(255);
        translate(width/2,height/2,0);
        stroke(0);
        noFill();
        box(200);
      } else {
        background(255);
        noStroke();
        fill(0);
        for (int x = 10; x < width; x+=10) {
          for (int y = 10; y < height; y+=10) {
            ellipse(x, y, 4, 4);
          }
        }
      }
    }
    
    void keyPressed(){
      if(key==' ') is_3d = !is_3d;
    }
    

    Since part of step three (in your original post) mentions a cube, I decided to draw a cube in the 3D view. Also notice that you can toggle between the 3D and 2D view by pressing space. As before, notice how clear the logic for this code is.

  • Answer ✓

    Steps 3 and 4 both deal with camera controls. For 3, you'd have needed the appropriate mouse functions, plus variables to save the starting mouse position, if we're doing rotation, and the amount of rotation done so far. For 4, a zoom variable, a call to scale(), and a event listener to catch the mouse scrolling.

    boolean is_3d;
    float zoom = 1;
    int saved_mouseX, saved_mouseY;
    boolean update_rotation = false;
    float rot_y, rot_x;
    
    void setup() {
      size(400, 400, P3D);
      smooth();
      is_3d = false;
    }
    
    void draw() {
      if (is_3d) {
        background(255);
        translate(width/2, height/2, 0);
        if (update_rotation) {
          rotateY(rot_y-map(saved_mouseX-mouseX, -width, width, -PI, PI));
          rotateX(rot_x+map(saved_mouseY-mouseY, -height, height, -PI, PI));
        } else {
          rotateY(rot_y);
          rotateX(rot_x);
        }
        stroke(0);
        noFill();
        scale(zoom);
        box(200);
      } else {
        background(255);
        noStroke();
        fill(0);
        for (int x = 10; x < width; x+=10) {
          for (int y = 10; y < height; y+=10) {
            ellipse(x, y, 4, 4);
          }
        }
      }
    }
    
    void end_rotation() {
      update_rotation = false;
      rot_y-=map(saved_mouseX-mouseX, -width, width, -PI, PI);
      rot_x+=map(saved_mouseY-mouseY, -height, height, -PI, PI);
    } 
    
    void keyPressed() {
      if (key==' ') is_3d = !is_3d;
      if (!is_3d) end_rotation();
    }
    
    void mousePressed() {
      if (is_3d) {
        saved_mouseX = mouseX;
        saved_mouseY = mouseY;
        update_rotation = true;
      }
    }
    
    void mouseReleased() {
      end_rotation();
    }
    
    void mouseWheel(MouseEvent event) {
      float e = event.getCount();
      zoom+=e/100.0;
    }
    

    Now that's getting pretty complicated. From here, you start talking a lot about dots and selecting them and planes and stuff. I highly suggest you write a Dot class if you want to keep working on this.

  • ??

    this is homework

    don't do it for him

  • @Chrisir Like I said just a pet project. I haven't done homework since '91. @TfGuy44 thanks for the response. This is a lot to go over. I'll get back to you once I've had time to look it over.

  • This obviously isn't going to be as easy as I thought. I intended the cube (mentioned in part 3) to be a cube of dots (ellipses). There doesn't seem to be a way to pass z coordinates on to the ellipse function. Anyway you recommend getting this accomplished?

  • edited January 2016 Answer ✓

    Yeah

    You can use points First

    Then write your own function ellipse3D or so with ellipse or sphere

    like

    pushMatrix();
    
    translate (x1,y1,z1);
    
    .....
    
    popMatrix();
    

    see reference

  • Answer ✓

    PM me

    Easy

  • Answer ✓

    ??

    actually, that was the instruction

    Try it

  • Ok...Give me another 3 months :)

  • edited January 2016

    you are a genius....

    I mean like

    void ellipse3D(float x1, float y1, float z1) { 
    
        // 
    
        pushMatrix();
    
        translate (x1,y1,z1);
    
        sphere (6); 
        // OR: ellipse(0,0,6,6); 
    
        popMatrix();
    
    }
    

    my... what do the kids learn at school nowadays

    Post your entire code

  • but again you don't cover precisely what you mean in the first place.....

  • Well as I said before I'm not a programmer.

  • ??

    So, what are you then?

  • float rotx = PI/4;
    float roty = PI/4;
    
    ArrayList<PVectorMy> l1 = new ArrayList();  
    
    class PVectorMy {
    
      float x1;
      float y1; 
      float z1;
    
      float u, v;
    
      PVectorMy( int x1_, int y1_, int z1_, 
        int u_, int v_  )
    
      {
    
        x1=x1_;
        y1=y1_;
        z1=z1_;
        u=u_;
        v=v_;
      }//constr
    }//class
    
    void setup() {
      size(640, 360, P3D);
      //   tex = loadImage("berlin-1.jpg");
      textureMode(NORMAL);
      TexturedCube();
    
      fill(255);
      stroke(color(44, 48, 32));
    }
    
    void draw() {
      background(0);
      noStroke();
      translate(width/2.0, height/2.0, -100);
      rotateX(rotx);
      rotateY(roty);
      scale(90);
    
      for (int i=0; i<l1.size(); i+=4) {
        PVectorMy p1 = l1.get(i); 
        PVectorMy p2 = l1.get(i+1);
        PVectorMy p3 = l1.get(i+2);
        PVectorMy p4 = l1.get(i+3);
    
        lerpPV(p1, p2);
        lerpPV(p2, p3);
        lerpPV(p3, p4);
        lerpPV(p4, p1);
      }
    }
    
    void lerpPV( PVectorMy p1, PVectorMy p2) { 
      for (int i = 0; i <= 10; i++) {
        float x = lerp(p1.x1, p2.x1, i/10.0) + 10;
        float y = lerp(p1.y1, p2.y1, i/10.0);
        float z = lerp(p1.z1, p2.z1, i/10.0);
        stroke(255); 
        strokeWeight(2.8);
        point(x, y, z);
      }
    }
    
    void TexturedCube() {
      // beginShape(QUADS);
      //  texture(tex);
    
      // Given one texture and six faces, we can easily set up the uv coordinates
      // such that four of the faces tile "perfectly" along either u or v, but the other
      // two faces cannot be so aligned.  This code tiles "along" u, "around" the X/Z faces
      // and fudges the Y faces - the Y faces are arbitrarily aligned such that a
      // rotation along the X axis will put the "top" of either texture at the "top"
      // of the screen, but is not otherwised aligned with the X/Z faces. (This
      // just affects what type of symmetry is required if you need seamless
      // tiling all the way around the cube)
    
      // +Z "front" face
      l1.add(new PVectorMy(-1, -1, 1, 0, 0));
      l1.add(new PVectorMy( 1, -1, 1, 1, 0));
      l1.add(new PVectorMy( 1, 1, 1, 1, 1));
      l1.add(new PVectorMy(-1, 1, 1, 0, 1));
    
      // -Z "back" face
      l1.add(new PVectorMy( 1, -1, -1, 0, 0));
      l1.add(new PVectorMy(-1, -1, -1, 1, 0));
      l1.add(new PVectorMy(-1, 1, -1, 1, 1));
      l1.add(new PVectorMy( 1, 1, -1, 0, 1));
    
      // +Y "bottom" face
      l1.add(new PVectorMy(-1, 1, 1, 0, 0));
      l1.add(new PVectorMy( 1, 1, 1, 1, 0));
      l1.add(new PVectorMy( 1, 1, -1, 1, 1));
      l1.add(new PVectorMy(-1, 1, -1, 0, 1));
    
      // -Y "top" face
      l1.add(new PVectorMy(-1, -1, -1, 0, 0));
      l1.add(new PVectorMy( 1, -1, -1, 1, 0));
      l1.add(new PVectorMy( 1, -1, 1, 1, 1));
      l1.add(new PVectorMy(-1, -1, 1, 0, 1));
    
      // +X "right" face
      l1.add(new PVectorMy( 1, -1, 1, 0, 0));
      l1.add(new PVectorMy( 1, -1, -1, 1, 0));
      l1.add(new PVectorMy( 1, 1, -1, 1, 1));
      l1.add(new PVectorMy( 1, 1, 1, 0, 1));
    
      // -X "left" face
      l1.add(new PVectorMy(-1, -1, -1, 0, 0));
      l1.add(new PVectorMy(-1, -1, 1, 1, 0));
      l1.add(new PVectorMy(-1, 1, 1, 1, 1));
      l1.add(new PVectorMy(-1, 1, -1, 0, 1));
    
      // endShape();
    }
    
    void mouseDragged() {
      float rate = 0.01;
      rotx += (pmouseY-mouseY) * rate;
      roty += (mouseX-pmouseX) * rate;
    }
    
  • Do you mean what do I do for a living?

  • no... rather why do you want a Program....?

  • edited January 2016

    Its a personal project of mine. I am trying to visualize the connections between 2 dimensional linear shapes in 3 dimensional space. Come to think of it I probably only need 2 planes but I would like to be able to draw lines in multiple planes, connect them, and then visualize the shapes from different angles by rotating/shifting the cube.

  • vague...

    With cube you just mean scene or the planes with the lines?

    And not a cube that I just did for you?! I wasted my time...

    The points in the planes where do they come from? Data? Csv? Or a Grid?

    the lines between the points: just lines or dotted line as I did for you??

  • edited January 2016

    I mean TFGuy44 did a lot for you...

    What is missing for you in his code?

    you wrote

    2 dimensional linear shapes in 3 dimensional space.

    Can you post the shapes?

    Or your code as far as you are now?

  • here are 2 sketches by me that use mouse to translate / rotate and zoom

    https://forum.processing.org/two/discussion/comment/60283/#Comment_60283

  • edited January 2016

    Q. The points in the planes where do they come from? Data? Csv? Or a Grid?

    A. Just a Grid. Think 3d graph paper without lines. Just points.

    Q. The lines between the points: just lines or dotted line as I did for you??

    A. The user creates lines by clicking on the points. When they click and hold on a point they get to choose an angle to connect to the next plane (45, 90, or 135)

    Q. Can you post the shapes or your code as far as you are now?

    A. The "shapes" are just lines between points. This is how it functions in 2D: https://forum.processing.org/two/discussion/comment/54674/#Comment_54674

  • you are not making sense...

    A. Just a Grid. Think 3d graph paper without lines. Just points.

    yes. but which points? Can you post the list of the points?

    A. The user creates lines by clicking on the points. When they click and hold on a point they get to choose an angle to connect to the next plane (45, 90, or 135)

    so then he clicks on a given origin point (in plane A) and chooses the angle and thus creating a new point on the opposite plane (plane B)?

    are you aware that the angles are nuts because 90° would be inside plane A and never hit plane B and that 135° degree would even be behind plane A and not going anywhere near plane A...?

    oh boy....

  • edited January 2016

    Does 90 degrees (perpendicular to the x,y viewing plane) not move the view closer to the observer? Where 270 takes them deeper into screen?

  • you were referring to drawing a new line to the other plane in this angle...

    now you're referring to move the camera.... ?

  • I mean, the user can start a line and draw a line himself, right?

    he can start only at an existing point, right?

    and he can end anywhere on the 2nd plane right, ?

    and where he ends a new point gets created on the 2nd plane?

    or can he draw the line only to an existing target point on the 2nd plane?

  • We are experiencing a disconnect in jargon. Forget for the moment the method with which you would accomplish this in Processing for a moment...

    Just image a 3D Cube made of points in space.

    Lines can be drawn between points in the same plane (x1, x2) OR Between points in different planes (z1, z2)

    A 90 degree line between z1 and z2 will create a line (perpendicular to the x, y plane) moving toward the user.

    Got it?

  • I think your getting it :) Yes the user can only draw the line to one of 3 existing points in the next plane 45, 90, 135. (only 90 will be initially viewable (see Optional section of original post) but 90, 45 and 135 are the only points accessible in each pane.

  • do you want to be 2 planes visible or would the cube consist of 10 planes

    or if it were a 10 x 10 cube had 10 planes?

  • Answer ✓

    Seriously, does no one listen to me? I suggested a Dot class ages ago. Yet no Dot class appears.

    class Dot {
      PVector p;
      color c;
      Dot(int px, int py, int pz) {
        p = new PVector(px, py, pz);
        c = color(random(255), random(255), random(255));
      }
      void draw() {
        pushMatrix();
        translate(p.x, p.y, p.z);
        fill(c);
        noStroke();
        box(4);
        popMatrix();
      }
    }
    
    ArrayList<Dot> dots = new ArrayList();
    float zoom = 1;
    int saved_mouseX, saved_mouseY;
    boolean update_rotation = false;
    float rot_y, rot_x;
    
    void setup() {
      size(400, 400, P3D);
      for (int x = -100; x<110; x+=50) {
        for (int y = -100; y<110; y+=50) {
          for (int z = -100; z<110; z+=50) {
            dots.add( new Dot(x, y, z) );
          }
        }
      }
    }
    
    void draw() {
      background(0);
      translate(width/2, height/2, 0);
      if (update_rotation) {
        rotateY(rot_y-map(saved_mouseX-mouseX, -width, width, -PI, PI));
        rotateX(rot_x+map(saved_mouseY-mouseY, -height, height, -PI, PI));
      } else {
        rotateY(rot_y);
        rotateX(rot_x);
      }
      stroke(255);
      noFill();
      scale(zoom);
      box(210);
      for( Dot dot : dots ) dot.draw();
    }
    
    void end_rotation() {
      update_rotation = false;
      rot_y-=map(saved_mouseX-mouseX, -width, width, -PI, PI);
      rot_x+=map(saved_mouseY-mouseY, -height, height, -PI, PI);
    } 
    
    void mousePressed() {
        saved_mouseX = mouseX;
        saved_mouseY = mouseY;
        update_rotation = true;
    }
    
    void mouseReleased() {
      end_rotation();
    }
    
    void mouseWheel(MouseEvent event) {
      float e = event.getCount();
      zoom+=e/100.0;
    }
    

    This is what we're talking about. Now the next step is going to be determining if the user has clicked on a Dot. This is not an easy problem to solve...

    http://www.openprocessing.org/sketch/7707

    ... oh wait.

    Now listen this time: You probably want to write a Connection class. One that draws a line that represents the connection between two Dots.

  • Answer ✓
    // https : // forum.processing.org/two/discussion/12955/interactive-rotating-cube-3d-graph-paper-with-rules#latest
    
    // States
    final int HELP = 0; // consts 
    final int GAME = 1;
    int state = GAME;   // current 
    
    // views 
    final int viewsTotal = 0;
    int view = viewsTotal;
    
    // spheres 
    SphereClass[][][] spheres = new SphereClass[6][6][6];
    
    // list with the LINES
    ArrayList<PVectorInt> listShape = new ArrayList(); 
    
    // rotation 
    float currentAngle1;      
    float zoomScale1=1.0;         
    
    PFont font1;
    boolean showGrid = false;  
    PVectorInt selected = new PVectorInt(-1, 0, 0);
    
    // --------------------------------------------------------
    // main funcs 
    
    void setup() {
      size(1400, 800, OPENGL);
    
      definespheres();
      background(111);
      font1 = createFont("Arial", 32);
      textFont(font1); 
    
      currentAngle1=0;
    } // func ---
    
    void draw() {
      switch (state) {
    
      case HELP:
        // to do  
        background(111);
        text("Help\n\nThis is the help..."
          +"\n\npress any key.", 
          32, 344);
        break;
    
      case GAME:
        playTheGame();   
        break;
      } // switch
    } // func draw()
    
    // ----------------------------------------------------
    
    void playTheGame() {
    
      background(111);
      lights();
    
      camera(0, 0, 810, 
        0, 0, 0, 
        0, 1, 0);
    
      scale (zoomScale1);
    
      //  translate(width/2, 0);
      rotateY(radians(currentAngle1));
    
    
    
      showTheGridDependingOnCurrentView();
    
      // show the selected sphere 
      if ( selected.x>-1) {
        // strokeWeight(5);
        spheres[ selected.x][ selected.y][ selected.z].col=color(255, 2, 2); 
        spheres[ selected.x][ selected.y][ selected.z].show(true);
      }
    
      strokeWeight(1);
    
      // rotation  
      if (keyPressed&&key=='r')
        currentAngle1++;
      if (keyPressed&&key=='l')
        currentAngle1--;
      // lookAtAngle();
    
      // 2D part / HUD  ---------------------------------------------
      camera();
      //  hint(DISABLE_DEPTH_MASK);
      //  hint(DISABLE_DEPTH_TEST);
      noLights();
      // textMode(MODEL);
      // textMode(SHAPE);
      textSize(22);
      fill(0); 
      text("Use r and l to rotate. Mouse wheel to zoom. "
        +"Mouse to make lines, and Backspace to remove lines.", 
        10, 20 );
      // text(mouseX + "," + mouseY, mouseX+7, mouseY-7);
    }
    
    // ------------------------------------------------------------------
    
    void showTheGridDependingOnCurrentView() {
    
      switch (view) {
    
      case viewsTotal:
    
        //   
        // show list with the LINES 
        // for (PVectorInt pvInt : listShape) {
        stroke(255, 2, 2);
        if (listShape.size()>1) 
          for (int i = 0; i < listShape.size()-1; i+=1) {
            PVectorInt pvInt1=listShape.get(i);
            PVectorInt pvInt2=listShape.get(i+1);
    
            SphereClass b1=spheres[pvInt1.x][ pvInt1.y][ pvInt1.z];
            SphereClass b2=spheres[pvInt2.x][ pvInt2.y][ pvInt2.z];
    
            line (b1.x, b1.y, b1.z, 
              b2.x, b2.y, b2.z);
          }// for 
    
        // show spheres : all
        for (int i = 0; i < spheres.length; i++) {
          for (int j = 0; j < spheres[i].length; j++) {
            for (int k = 0; k < spheres[i][j].length; k++) {
              //          if (selected.x==i&&selected.y==j&&selected.z==k)
              //            strokeWeight(5); 
              //          else
              //            strokeWeight(1); 
              spheres[i][ j][k].show(false);
            }
          }
        }// for
        break; 
    
      default : 
        // error 
        break;
      } // switch
    } // func 
    
    // ----------------------------------------------------
    // input funcs
    
    void keyPressed () {
    
      switch (state) {
    
      case HELP : 
        state = GAME; 
        break; 
    
      case GAME : 
        if (key!=CODED) {
          // not CODED -----------------------------------
          if (key=='X') {
            // reset  
            definespheres();
          } else if (key == 's') {
            showGrid=!showGrid;
          } else if (key == BACKSPACE) {
            if (listShape.size()>0) {
              listShape.remove(listShape.size()-1);
              selected = new PVectorInt(-1, 0, 0); // reset
            }
          } else {
            // do nothing
          }
        } else {
          // if (key==CODED) { --------------------------------------------
          //
          switch (keyCode) {
    
          case java.awt.event.KeyEvent.VK_F1 : 
            // F1 
            state = HELP; 
            break; 
    
          case java.awt.event.KeyEvent.VK_PAGE_UP : 
            zoomScale1-=.01; 
            break; 
    
          case java.awt.event.KeyEvent.VK_PAGE_DOWN : 
            zoomScale1+=.01; 
            break; 
    
          default : 
            // do nothing 
            break;
          } // switch
        } // else
    
        break;
      } // switch 
      //
    } // func 
    
    // ----------------------------------------------------
    // misc funcs
    
    void definespheres() {
      // define spheres
      //int k2=0; 
      //char letter=' '; 
      for (int i = 0; i < spheres.length; i++) {
        for (int j = 0; j < spheres[i].length; j++) {
          for (int k = 0; k < spheres[i][j].length; k++) {
            // prepare values 
            color currentCol = color (255); //  color (random(255), random(255), random(255));
            boolean exist = true; 
            //        // the percentage 
            //        if (random(100) > 50) { 
            //          exist = true;
            //        } else
            //          exist = false;
            //        if (k2<initText.length())
            //          letter = initText.charAt(k2);
            //        k2++;  
            // create a sphere   
            spheres[i][ j][k] = new SphereClass( 
              -200 + i*(height/10), 
              -185 + j*(height/10), 
              -70 + k*(height/10), 
              currentCol, 
              exist);
          }
        }
      } // for
    } // func 
    
    // ----------------------------------------
    
    void mousePressed() {
    
      //PVectorInt result = new PVectorInt(0, 0, 0);
    
      for (int i = 0; i < spheres.length; i++) {
        for (int j = 0; j < spheres[i].length; j++) {
          for (int k = 0; k < spheres[i][j].length; k++) {
    
            if (dist(mouseX, mouseY, spheres[i][j][k].scX, spheres[i][j][k].scY) < 12) {
              selected = new PVectorInt( i, j, k); 
              listShape.add ( new  PVectorInt( i, j, k)); 
              //println(listShape.size());
              return; // leave here
            }
          }
        }
      }
    }
    
    void mouseWheel(MouseEvent event) {
    
      //This method controls zoomScale1 variable
    
      if (event.getCount()==-1)
        zoomScale1 += 0.1;
      else if (event.getCount()==1) {
        if (zoomScale1>=.1)
          zoomScale1 -= 0.1;
      }
    
      // check lower boundary 
      if (zoomScale1<.1)
        zoomScale1 = .1;
      println("Scale Level: "+zoomScale1);
    } 
    
    // =====================================================
    // classes
    
    class SphereClass {
    
      // this class represents one Box / Cell
    
      float x; 
      float y; 
      float z; 
    
      float scX, scY; 
    
      color col; 
      color defaultCol; 
      boolean exist = true; 
    
      // constr
      SphereClass(float x_, float y_, float z_, 
        color col_, 
        boolean exist_) {
        x = x_; 
        y = y_; 
        z = z_; 
        col = col_;
        defaultCol = col; 
    
        exist = exist_; 
        //letter = letter_;
      } // constr
    
      void show(boolean showBox) {
        if (exist||showGrid) {
          pushMatrix(); 
          translate(x, y, z); 
    
          fill(col); 
          noStroke(); 
          sphere(7);
          col = defaultCol;
    
          // the sphere / box was drawn at (0, 0, 0), store that location
          scX = screenX(0, 0, 0); 
          scY = screenY(0, 0, 0);
    
          popMatrix();
        }
      } // method
    } // class 
    
    // ==============================================================
    
    class PVectorInt {
      // it's like a PVector but int (not float)
      // this is a compact form to store a 3D index
      int x, y, z; 
      PVectorInt(int x_, int y_, int z_) {
        x=x_; 
        y=y_; 
        z=z_;
      } // constr
    }
    // =============================================================
    
  • edited February 2016 Answer ✓

    I implemented right mouse button and a small menu for 90, 45, 135 now....

    // https : // 
    // forum.processing.org/two/discussion/12955/interactive-rotating-cube-3d-graph-paper-with-rules#latest
    
    // States:
    // consts / numbers must be unique
    final int HELP   = 0; // help 
    final int GAME   = 1; // standard: selecting spheres with the mouse
    final int DIALOG = 2; // select an angle in a dialog
    int state = GAME;   // current 
    
    // views 
    final int viewsTotal = 0;   // consts / numbers must be unique
    final int viewsPlane0 = 1;
    final int viewsPlane2 = 2;
    int view = viewsTotal;
    
    // spheres 
    SphereClass[][][] spheres = new SphereClass[6][6][6];
    
    // list with the LINES
    ArrayList<PVector> listShape = new ArrayList(); 
    
    // rotation 
    float currentAngle1;      
    float zoomScale1=1.0;         
    
    PFont font1;
    boolean showGrid = false;  
    PVectorInt selected = new PVectorInt(-1, 0, 0);
    
    int currentPlane = 6-1; 
    
    // --------------------------------------------------------
    // main funcs 
    
    void setup() {
      size(1400, 800, OPENGL);
    
      definespheres();
      background(111);
      font1 = createFont("Arial", 32);
      textFont(font1); 
    
      currentAngle1=0;
    } // func ---
    
    void draw() {
      switch (state) {
    
      case HELP:
        // to do  
        background(111);
        text("Help\n\nThis is the help..."
          +"\n\npress any key.", 
          32, 344);
        break;
    
      case GAME:
        playTheGame();   
        break;
    
      case DIALOG:
        // 
        background(111);
        camera();
        noLights(); 
        //fill(255, 2, 2); 
        //rect(20, 300, 230, 220);
        fill(255); //  white 
        text("degrees of arc (45, 90, 135)\n\nPlease select \n"
          +"     1 for 45, \n"
          +"     2 for 90 and \n"
          +"     3 for 135 degree..."
          +"\n\nThank you...", 
          32, 344, 
          210, 300);
        break;
      } // switch
    } // func draw()
    
    // ----------------------------------------------------
    
    void playTheGame() {
    
      background(111);
      lights();
    
      camera(0, 0, 810, 
        0, 0, 0, 
        0, 1, 0);
    
      scale (zoomScale1);
    
      //  translate(width/2, 0);
      rotateY(radians(currentAngle1));
    
      showTheGridDependingOnCurrentView();
    
      // show the selected sphere 
      if ( selected.x>-1) {
        // strokeWeight(5);
        spheres[ selected.x][ selected.y][ selected.z].col=color(255, 2, 2); 
        spheres[ selected.x][ selected.y][ selected.z].show(false);
      }
    
      strokeWeight(1);
    
      // rotation  
      if (keyPressed&&key=='r')
        currentAngle1++;
      if (keyPressed&&key=='l')
        currentAngle1--;
      // lookAtAngle();
    
      // 2D part / HUD  ---------------------------------------------
      camera();
      //  hint(DISABLE_DEPTH_MASK);
      //  hint(DISABLE_DEPTH_TEST);
      noLights();
      // textMode(MODEL);
      // textMode(SHAPE);
      textSize(14);
      fill(0); 
      text("Use r and l to rotate. Mouse wheel to zoom. "
        +"Mouse to make lines, and Backspace to remove lines. \n"
        +"Use 0, 1, 2 for different views. Active plane = "
        +currentPlane
        +".", 
        10, 20 );
      // text(mouseX + ", " + mouseY, mouseX+7, mouseY-7);
    }
    
    // ------------------------------------------------------------------
    
    void showTheGridDependingOnCurrentView() {
    
      // show list with the LINES 
      // for (PVectorInt pvInt : listShape) {
      stroke(255, 2, 2); // red 
      if (listShape.size()>1) 
        for (int i = 0; i < listShape.size()-1; i+=1) {
          PVector b1=listShape.get(i);
          PVector b2=listShape.get(i+1);
    
          //SphereClass b1=spheres[pvInt1.x][ pvInt1.y][ pvInt1.z];
          //SphereClass b2=spheres[pvInt2.x][ pvInt2.y][ pvInt2.z];
    
          line (b1.x, b1.y, b1.z, 
            b2.x, b2.y, b2.z);
        }// for 
    
      switch (view) {
    
      case viewsTotal:
        // show spheres : all
        for (int i = 0; i < spheres.length; i++) {
          for (int j = 0; j < spheres[i].length; j++) {
            for (int k = 0; k < spheres[i][j].length; k++) {
              if (k==currentPlane) 
                spheres[i][ j][k].show(true);
              else 
              spheres[i][ j][k].show(false);
            }
          }
        }// for
        break; 
    
      case viewsPlane0:
        // show spheres 
        for (int i = 0; i < spheres.length; i++) {
          for (int j = 0; j < spheres[i].length; j++) {
            //for (int k = 0; k < spheres[i][j].length; k++) {
            //          if (selected.x==i&&selected.y==j&&selected.z==k)
            //            strokeWeight(5); 
            //          else
            //            strokeWeight(1); 
            int k=currentPlane;
            spheres[i][ j][ k ].show(false);
            // }
          }
        }// for
        break; 
    
      case viewsPlane2:  
        // show spheres 
        //  currentPlane=spheres[0][0].length-1; // last plane !!!!! 
        for (int i = 0; i < spheres.length; i++) {
          for (int j = 0; j < spheres[i].length; j++) {
            //for (int k = 0; k < spheres[i][j].length; k++) {
            int k = currentPlane; 
            spheres[i][ j][ k ].show(false);
            // }
          }
        }// for
        break; 
    
      default : 
        // error 
        println("error number 199"); 
        break;
      } // switch
    } // func 
    
    // ----------------------------------------------------
    // input funcs
    
    void keyPressed () {
    
      switch (state) {
    
      case HELP : 
        state = GAME; 
        break; 
    
      case GAME : 
        if (key!=CODED) {
          // not CODED -----------------------------------
          if (key=='X') {
            // reset  
            definespheres();
          } else if (key == 's') {
            showGrid=!showGrid;
          } else if (key == '0') {
            view = viewsTotal;
          } else if (key == '1') {
            view = viewsPlane0;
          } else if (key == '2') {
            view = viewsPlane2;
          } else if (key == BACKSPACE) {
            if (listShape.size()>0) {
              listShape.remove(listShape.size()-1);
              selected = new PVectorInt(-1, 0, 0); // reset
            }
          } else {
            // do nothing
          }
        } else {
          // if (key==CODED) { --------------------------------------------
          //
          switch (keyCode) {
    
          case java.awt.event.KeyEvent.VK_F1 : 
            // F1 
            state = HELP; 
            break; 
    
          case java.awt.event.KeyEvent.VK_PAGE_UP : 
            zoomScale1-=.01; 
            break; 
    
          case java.awt.event.KeyEvent.VK_PAGE_DOWN : 
            zoomScale1+=.01; 
            break; 
    
          default : 
            // do nothing 
            break;
          } // switch
        } // else
        break;
    
      case DIALOG:
        // 
    
        switch (key) {
        case '1':
          //
          SphereClass sphereTemp = spheres[ selected.x][ selected.y][currentPlane]; 
          listShape.add ( new  PVector( sphereTemp.x-33, sphereTemp.y, sphereTemp.z-33));
          sphereTemp=null;
          break; 
    
        case '2':
          if (currentPlane>0) {
            currentPlane--;
            sphereTemp = spheres[ selected.x][ selected.y][ currentPlane]; 
            listShape.add ( new  PVector( sphereTemp.x, sphereTemp.y, sphereTemp.z));
            sphereTemp=null;
            selected.z=currentPlane;
          } else { 
            println("last plane, you can't go on.");
          }
          break; 
    
        case '3':
          //
          sphereTemp = spheres[ selected.x][ selected.y][currentPlane]; 
          listShape.add ( new  PVector( sphereTemp.x+33, sphereTemp.y, sphereTemp.z-33));
          sphereTemp=null;
          break;
        } //switch(key) 
        // reset 
        state=GAME; // reset 
        break;
        //
      } // switch (state) { 
      //
    } // func 
    
    // ----------------------------------------------------
    // misc funcs
    
    void definespheres() {
      // define spheres
      //int k2=0; 
      //char letter=' '; 
      for (int i = 0; i < spheres.length; i++) {
        for (int j = 0; j < spheres[i].length; j++) {
          for (int k = 0; k < spheres[i][j].length; k++) {
            // prepare values 
            color currentCol = color (111); //  color (random(255), random(255), random(255));
            boolean exist = true; 
            //        // the percentage 
            //        if (random(100) > 50) { 
            //          exist = true;
            //        } else
            //          exist = false;
            //        if (k2<initText.length())
            //          letter = initText.charAt(k2);
            //        k2++;  
            // create a sphere   
            spheres[i][ j][k] = new SphereClass( 
              -200 + i*(height/10), 
              -185 + j*(height/10), 
              -70 + k*(height/10), 
              currentCol, 
              exist);
          }
        }
      } // for
    } // func 
    
    // ----------------------------------------
    
    void mousePressed() {
    
      switch (state) {
    
      case HELP :
        // go back 
        state = GAME; 
        break; 
    
      case GAME : 
        if (mouseButton == LEFT) {
          // select a sphere 
          for (int i = 0; i < spheres.length; i++) {
            for (int j = 0; j < spheres[i].length; j++) {
              //for (int k = 0; k < spheres[i][j].length; k++) {
              int k=currentPlane; 
    
              if (dist(mouseX, mouseY, spheres[i][j][k].scX, spheres[i][j][k].scY) < 12) {
                selected = new PVectorInt( i, j, k); 
                SphereClass sphereTemp = spheres[ i ][ j ][ k ]; 
                listShape.add ( new  PVector( sphereTemp.x, sphereTemp.y, sphereTemp.z));
                sphereTemp=null;
                // listShape.add ( new PVectorInt( i, j, k)); 
                //println(listShape.size());
                return; // leave here
                // }
              }
            }
          }//for
        } //if
        else if (mouseButton == RIGHT) {
          //
          state=DIALOG;
        }//else 
        break;
      } // switch
    }//func
    
    void mouseWheel(MouseEvent event) {
    
      //This method controls zoomScale1 variable
    
      if (event.getCount()==-1)
        zoomScale1 += 0.1;
      else if (event.getCount()==1) {
        if (zoomScale1>=.1)
          zoomScale1 -= 0.1;
      }
    
      // check lower boundary 
      if (zoomScale1<.1)
        zoomScale1 = .1;
      //println("Scale Level: "
      //  +zoomScale1);
    } 
    
    // =====================================================
    // classes
    
    class SphereClass {
    
      // this class represents one Box / Cell
    
      float x; 
      float y; 
      float z; 
    
    
      float scX, scY; 
    
      color col; 
      color defaultCol; 
      boolean exist = true; 
    
      // constr
      SphereClass(float x_, float y_, float z_, 
        color col_, 
        boolean exist_) {
        x = x_; 
        y = y_; 
        z = z_; 
        col = col_;
        defaultCol = col; 
    
        exist = exist_; 
        //letter = letter_;
      } // constr
    
      void show(boolean showBox) {
        if (exist||showGrid) {
          pushMatrix(); 
          translate(x, y, z); 
    
          if (showBox) 
            fill(0, 0, 255);//blue 
          else fill(col); 
    
          noStroke(); 
          sphere(7);
          col = defaultCol;
    
          // the sphere / box was drawn at (0, 0, 0), store that location
          scX = screenX(0, 0, 0); 
          scY = screenY(0, 0, 0);
    
          popMatrix();
        }
      } // method
    } // class 
    
    // ==============================================================
    
    class PVectorInt {
      // it's like a PVector but int (not float)
      // this is a compact form to store a 3D index
      int x, y, z; 
      PVectorInt(int x_, int y_, int z_) {
        x=x_; 
        y=y_; 
        z=z_;
      } // constr
    }
    // ===============================================================
    
  • Wow. This is very close! Apparently this is well out of my depth as an amateur programmer. I will be in contact with both of you shortly.

  • Answer ✓

    just ask what you need more

  • What is your goal with this?

    Is this a game, a riddle or a drawing program...?

  • What do you miss from the code?

  • edited February 2016

    @Chrisir thanks for your interest and contact info. Will send you a private email

Sign In or Register to comment.