Search code examples
pythonpyprocessing

How correctly draw boxes in pyprocessing?


I'm trying to write a very basic box drawing program using pyprocessing, but a condition to check if the mouse is within a box fails, when the logic looks ok:

#!/usr/bin/env python
from pyprocessing import *

S = 20
W = 5
H = 5

data = [[0] * W] * H

def setup():
    size(W*(S+5),H*(S+5))

def draw():
    background(0)
    for y in xrange(H):
        for x in xrange(W):
            fill(data[x][y] * 255)
            rect(x*S,y*S,S,S)

def mouseDragged():
    for y in xrange(H):
        for x in xrange(W):
            xs = x * S
            ys = y * S
            # this doesn't behave as expected: it should draw a single box if the condition is met, not the whole row
            if (mouse.x >= xs) and (mouse.x <= (xs+S)) and (mouse.y >= ys and mouse.y <= (ys+S)):
                if key.pressed:
                    data[x][y] = 0
                else:   
                    data[x][y] = 1

run()

I've tried the same approach using the Java version of Processing and it works as expected:

int S = 20;
int W = 5;
int H = 5;

int[][] data = new int[W][H];

void setup(){
  size(100,100);
  noStroke();
}

void draw(){
  background(0);
  for (int y = 0 ; y < H; y++){
    for (int x = 0 ; x < W; x++){
      fill(data[x][y] * 255);
      rect(x*S,y*S,S,S);
    }
  }
}
void mouseDragged(){
  for (int y = 0 ; y < H; y++){
    for (int x = 0 ; x < W; x++){
      int xs = x * S;
      int ys = y * S;
      if ((mouseX > xs) && (mouseX < (xs+S)) && (mouseY >= ys && mouseY <= (ys+S))){
        data[x][y] = 1;
      }
    }
  }
}

Similar behaviour in JS:

var S = 20;
var W = 5;
var H = 5;

var data = new Array(W);

function setup(){
  createCanvas(100,100);
  noStroke();
  for (var i = 0 ; i < H; i++) data[i] = [0,0,0,0,0];
  
}

function draw(){
  background(0);
  for (var y = 0 ; y < H; y++){
    for (var x = 0 ; x < W; x++){
      fill(data[x][y] * 255);
      rect(x*S,y*S,S,S);
    }
  }
}
function mouseDragged(){
  for (var y = 0 ; y < H; y++){
    for (var x = 0 ; x < W; x++){
      var xs = x * S;
      var ys = y * S;
      if ((mouseX > xs) && (mouseX < (xs+S)) && (mouseY >= ys && mouseY <= (ys+S))){
        data[x][y] = 1;
      }
    }
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.4.23/p5.min.js"></script>

Am I writing the box bounds condition correctly in Python ? If so, is there a bug with pyprocessing ? How can I get past it ?

I'm using pyprocessing.version '0.1.3.22'


Solution

  • Trying to be lazy is the issue:

    data = [[0] * W] * H
    

    This doesn't simply create a nested array, it copies the references of the first array ([0]), so when I modify one value in one row, the whole row is modified.

    Since I'm super experienced with python, I've initialised the array in a probably a non-pythonic way:

    data = []
    for y in xrange(H):
        data.append([])
        for x in xrange(W):
            data[y].append(0)
    

    So the full working code is:

    #!/usr/bin/env python
    from pyprocessing import *
    
    S = 20
    W = 5
    H = 5
    
    # data = [[0] * W] * H #trouble
    data = []
    for y in xrange(H):
        data.append([])
        for x in xrange(W):
            data[y].append(0)
    
    def setup():
        size(W*(S),H*(S))
    
    def draw():
        background(0)
        for y in xrange(H):
            for x in xrange(W):
                fill(data[x][y] * 255)
                rect(x*S,y*S,S,S)
    
    def mouseDragged():
        for y in xrange(H):
            for x in xrange(W):
                xs = x * S
                ys = y * S
                if (mouse.x >= xs) and (mouse.x <= (xs+S)) and (mouse.y >= ys and mouse.y <= (ys+S)):
                    if key.pressed:
                        data[x][y] = 0
                    else:   
                        data[x][y] = 1
    
    run()