Creating Bounds in the Draw Function

I was hoping to make a simple “bound mode” for the Draw Function, so that when items slid off-Window due to being translated too far, they would reappear on the opposite side of the Window.

I tried to do it, as in the following code, but this approach didn’t work. If anyone could point me to another approach, I would appreciate it.

(
w = Window("", Rect(0, 900, 700, 500));
w.drawFunc_({
	100.do{|x|
		var xArray;
		xArray = Pen.matrix[4] > 100;
		if (xArray == true, {
			Pen.matrix[4] = 0;
		});
		Pen.translate(10, 1);
		Pen.addRect(Rect(0, 0, 10, 10));
	    Pen.fill;
	};
});
w.front;
)

Hi,
the easiest and most common technique is to just wrap the coordinates for your rectangles using modulo (%). Like this…

(
w = Window("", Rect(0, 900, 700, 500));
w.drawFunc_({
    333.do{|x|
        Pen.addRect(Rect(x*10%w.bounds.width, x, 10, 10));
    };
    Pen.fill;
});
w.front;
)

A simple animation example that wrap both window width and height…

(
var dx= -4, dy= -1.4;  //directions - try different values
var x= 0, y= 0;  //start pos
var w = Window("", Rect(0, 900, 700, 500));
w.drawFunc_({
    Pen.fillRect(Rect(x%w.bounds.width, y%w.bounds.height, 10, 10));
    x= x+dx;
    y= y+dy;
});
Routine({while({w.isClosed.not}, {w.refresh; (1/60).wait})}).play(AppClock);
w.front;
)

But if i’m misunderstanding and you really need to translate and reset the whole matrix, then please explain more in detail what you’re trying to do.

Thanks for the response!
I think my reason for trying to address the Matrix directly is so I can make use of other methods (like Pen.rotate and Pen.scale) and also deal with slightly more complex shapes.

It sounds like this might be a challenge, though?

I think my reason for trying to address the Matrix directly is so I can make use of other methods (like Pen.rotate and Pen.scale) and also deal with slightly more complex shapes.

You can still manipulate point objects before you do the border check and draw them. There are ways to translate, rotate and scale individual Point objects. And then you know which will end up outside of the window boundaries.

//wrapped diagonal line
(
w = Window("", Rect(0, 900, 700, 500));
w.drawFunc_({
    1000.do{|x|
        var position = Point(x, x);  //diagonal
        //position = position + 100;  //translate (offset)
        position = position.rotate(x*0.0003);  //rotate (NOTE Point.rotate instead of Pen.rotate)
        //position = position * 10;  //scale (step size)
        Pen.addRect(Rect(position.x%w.bounds.width, position.y%w.bounds.height, 10, 10));
    };
    Pen.fill;
});
w.front;
)

//another approach - spiral wrapping around window bounds
(
w = Window("", Rect(0, 900, 700, 500));
w.drawFunc_({
    var offset_x = 350;  //translate x
    var offset_y = 250;  //translate y
    var rotation_x = 0.01;
    var rotation_y = 0.0101;
    2100.do{|x|
        var radius = 10+(x*0.2);  //growing (scale)
        var position = Point(
            sin(x*rotation_x)*radius+offset_x,
            cos(x*rotation_y)*radius+offset_y
        );
        position = position%Point(w.bounds.width, w.bounds.height);  //same as above just written differently with a single % and a Point object
        Pen.addRect(Rect(position.x, position.y, 10, 10));
    };
    Pen.fill;
});
w.front;
)

Also, we could’ve used an if statement and check if any position is out-of-bounds and then wrap it around, but it’s easier to just apply % on all positions.

It sounds like this might be a challenge, though?

Yes, with Pen.rotate it quickly gets hairy. If you translate, rotate or scale the matrix with Pen, your rectangle (or rather the point object that holds the xy position of where we will draw the rectangle), won’t know that the drawing area has been transformed. The two coordinate systems aren’t linked. So we’ll have to manually keep track of the matrix operations we perform and undo them - calculate our way back to window coordinates. It’s a bit like WorldToScreenPoint and ScreentoWorldPoint methods found in some 3D programs.

Here a very rough example showing it can be done - but really - don’t.

(
w = Window("", Rect(0, 900, 700, 500));
w.drawFunc_({
    var trans = Point(w.bounds.width*0.5, w.bounds.height*0.5);
    Pen.translate(trans.x, trans.y);
    350.do{|x|
        var position = Point(x, x);  //diagonal
        var shadow = position.copy;
        
        Pen.rotate(0.03);
        shadow = shadow.rotate(x*0.03);  //should match the matrix rotation above
        
        shadow = shadow + trans;
        shadow = shadow % Point(w.bounds.width, w.bounds.height);  //wrap around bounds
        shadow = shadow - trans;
        shadow = shadow.rotate(x* -0.03);  //undo rotation
        
        //unbounded rectangles drawn in black - disappears
        Pen.fillColor = Color.black;
        Pen.fillRect(Rect(position.x, position.y, 10, 10));
        
        //wrapped rectangles in blue - wraps around window bounds
        Pen.fillColor = Color.blue;
        Pen.fillRect(Rect(shadow.x, shadow.y, 5, 5));
    };
});
w.front;
)

_f

#|
fredrikolofsson.com musicalfieldsforever.com